如何取消这些承诺的嵌套? [英] How to unnest these Promises?
问题描述
我有一个向服务器发出请求的功能。如果请求失败,我要:
1.记录错误
2.运行终端命令
2.1记录命令失败或成功
I have a function that makes a request to a server. If the request fails, I want to: 1. log the error 2. run a terminal command 2.1 log if the command failed or succeeded
要实现这一点,我需要以下代码:
To achieve this I have the following code:
const createRequest = ( { request, logger, terminal } ) => ( { endpoint, timeout } ) =>
request.get( endpoint, { timeout } )
.then( response =>
logger.info( { event: "Heartbeat request succeeded.", status: response.status } )
)
.catch( err =>
logger.error( { event: "Heartbeat request failed.", err } )
.then( ( ) => terminal.runAsync( "pm2 restart myAPI" ) )
.then( ( ) => logger.info( { event: "Restarted API." } ) )
.catch( err => logger.error( { event: "Failed to restart API.", err } ) )
);
现在,有几件事需要注意:
-日志记录是异步的(发送信息到远程服务器)
-运行终端命令是异步
-使请求(显然)是异步
Now, there are a few things to notice: - logging is async ( sends info to a remote server ) - running the terminal command is async - making the request is ( obviously ) async
我的问题是我的渔获里面有一个Promise,这意味着我有嵌套。
现在,我强烈反对应许的嵌套,所以我真的想摆脱它,但我只是不知道如何。
The problem I have is that my catch has a Promise inside, which means I have nesting. Now, I am strongly against nesting of promises, so I really want to get rid of that, but I just don't see how.
- 是否有可能摆脱
catch
内的嵌套承诺? - 是否这样?
- Is it possible to get rid of nesting promises inside a
catch
? - If so how?
推荐答案
问题?
我的问题是我的渔获物内部有一个Promise,这意味着我有嵌套。现在,我强烈反对应许的嵌套,所以我真的想摆脱它,但是我只是不知道如何。
The problem I have is that my catch has a Promise inside, which means I have nesting. Now, I am strongly against nesting of promises, so I really want to get rid of that, but I just don't see how.
– Flame_Phoenix
– Flame_Phoenix
问题是您认为自己有问题–或者您是在StackOverflow而不是CodeReview 。 链接的文章显示了您对嵌套的Promise采取幼稚的看法
The problem is that you think you have a problem – or maybe that you posted this question on StackOverflow instead of CodeReview. The article you linked shows where you adopt a naive view about nested promises
您会得到一大堆彼此嵌套的承诺:
You get a whole bundle of promises nested in eachother:
loadSomething().then(function(something) {
loadAnotherthing().then(function(another) {
DoSomethingOnThem(something, another);
});
});
这样做的原因是因为您需要对两个诺言的结果都做点事情,所以您不能链接它们,因为then()仅传递了前一个返回的结果。
The reason you’ve done this is because you need to do something with the results of both promises, so you can’t chain them since the then() is only passed the result of the previous return.
您这样做的真正原因是因为您没有不知道 Promise.all()
方法。
The real reason you’ve done this is because you don’t know about the Promise.all()
method.
–代码猴子, http://taoofcode.net
否, Promise.all
只能有时替换嵌套的承诺。一个简单的反例–在这里,一个承诺的价值取决于另一个,因此两个必须进行排序
No, Promise.all
can only sometimes replace nested promises. A simple counter-example – here, one promise's value depends on the the other and so the two must be sequenced
getAuthorByUsername (username) .then (a => getArticlesByAuthorId (a.id))
Nesting promises is not always necessary, but calling it an "anti-pattern" and encouraging people to avoid it before they know the difference is harmful, imo.
语句不起作用
其他链接文章显示了您可能再次被误导的地方
The other linked article shows where you may have been misguided again
别误会我的意思,异步/等待并不是世界上所有邪恶的源头。经过几个月的使用,我实际上学会了喜欢它。因此,如果您舒适地编写命令式代码,那么学习如何使用async / await来管理异步操作可能是个不错的选择。
Don’t get me wrong, async/await is not the source of all evil in the world. I actually learned to like it after a few months of using it. So, if you feel confortable writing imperative code, learning how to use async/await to manage your asynchronous operations might be a good move.
但是如果您喜欢promises并且您想要学习越来越多的函数式编程原理并将其应用到您的代码中,您可能希望完全跳过异步/等待代码,停止思考必要的命令,而转向这种新的旧模式。
But if you like promises and you like to learn and apply more and more functional programming principles to your code, you might want to just skip async/await code entirely, stop thinking imperative and move to this new-old paradigm.
– Gabriel Montes
– Gabriel Montes
这只是没有任何意义。如果您查看JavaScript中的所有命令式关键字,就会发现它们都不会对值求值。为了说明我的意思,请考虑
Only this doesn't make any sense. If you look at all of the imperative keywords in JavaScript, you'll notice none of them evaluate to a value. To illustrate what I mean, consider
let total = if (taxIncluded) { total } else { total + (total * tax) }
// SyntaxError: expected expression, got keyword 'if'
在另一个表达式中间使用 if
Or if we try to use if
in the middle of another expression
makeUser (if (person.name.length === 0) { "anonymous" } else { person.name })
// SyntaxError: expected expression, got keyword 'if'
这是因为 if
是声明,并且永远不会求值–相反,它只能依靠副作用。
That's because if
is a statement and it never evaluates to a value – instead, it can only rely on side effects.
if (person.name.length === 0)
makeUser ("anonymous") // <-- side effect
else
makeUser (person.name) // <-- side effect
在以下
永远不会求值。相反,它依靠副作用来计算 sum
Below for
never evaluates to a value. Instead it relies on side effects to compute sum
let sum = 0
let numbers = [ 1, 2, 3 ]
for (let n of numbers)
sum = sum + n // <-- side effect
console.log (sum) // 6
do $ c也是如此$ c>,
而
,开关
,甚至返回
和所有其他命令式关键字-它们都是语句,因此依赖于副作用来计算值。
The same is true for do
, while
, switch
, even return
and all of the other imperative keywords – they're all statements and therefore rely upon side effects to compute values.
然后求值的值? 表达式评估为值
What evaluates to a value then? Expressions evaluate to a value
1 // => 1
5 + 5 // => 10
person.name // => "bobby"
person.name + person.name // => "bobbybobby"
toUpper (person.name) // => "BOBBY"
people .map (p => p.name) // => [ "bobby", "alice" ]
async
和 await
不是语句
async
and await
are not statements
您可以将异步函数分配给变量
You can assign an asynchronous function to a variable
const f = async x => ...
或者您可以将异步函数作为参数传递
Or you can pass an asyncrhonous function as an argument
someFunc (async x => ... )
即使 async
函数不返回任何内容, async
仍然保证我们将收到Promise值
Even if an async
function returns nothing, async
still guarantees we will receive a Promise value
const f = async () => {}
f () .then (() => console.log ("done"))
// "done"
您可以等待
一个值并将其分配给变量
You can await
a value and assign it to a variable
const items = await getItems () // [ ... ]
或者您可以等待
另一个表达式中的值
Or you can await
a value in another expression
items .concat (await getMoreItems ()) // [ ... ]
这是因为 async
/ await
形式的表达式可以与功能样式一起使用。如果您尝试学习功能样式并避免 async
和 await
,那仅仅是因为您被误导了。如果 async
和 await
仅是命令式的,这样的事情将永远不可能
It's because async
/await
form expressions that they can be used with functional style. If you are trying to learn functional style and avoid async
and await
, it is only because you've been misguided. If async
and await
were imperative style only, things like this would never be possible
const asyncUnfold = async (f, initState) =>
f ( async (value, nextState) => [ value, ...await asyncUnfold (f, nextState) ]
, async () => []
, initState
)
真实示例
这是一个实际的示例,其中我们有一个记录数据库,我们希望执行递归查找或其他操作。
Here's a practical example where we have a database of records and we wish to perform a recursive look-up, or something...
const data =
{ 0 : [ 1, 2, 3 ]
, 1 : [ 11, 12, 13 ]
, 2 : [ 21, 22, 23 ]
, 3 : [ 31, 32, 33 ]
, 11 : [ 111, 112, 113 ]
, 33 : [ 333 ]
, 333 : [ 3333 ]
}
异步函数 Db.getChildren
站在您和您的数据之间。您如何查询节点及其后代的所有 ?
An asynchronous function Db.getChildren
stands between you and your data. How do you query a node and all of its descendants?
const Empty =
Symbol ()
const traverse = (id) =>
asyncUnfold
( async (next, done, [ id = Empty, ...rest ]) =>
id === Empty
? done ()
: next (id, [ ...await Db.getChildren (id), ...rest ])
, [ id ]
)
traverse (0)
// => Promise [ 0, 1, 11, 111, 112, 113, 12, 13, 2, 21, 22, 23, 3, 31, 32, 33, 333, 3333 ]
从 JavaScript开发人员天堂发送的一个纯程序,用Montes的话来说就是。它是使用函数表达式编写的,错误相应地冒出,我们什至不必触摸。然后
。
A pure program sent from the "heaven of JavaScript developers", to put it in the words of Montes. It's written using a functional expression, errors bubble up accordingly, and we didn't even have to touch .then
.
我们可以使用命令式风格编写相同的程序。或者我们也可以使用来编写功能样式。然后
。我们可以用各种方式来编写它,我想这就是关键–感谢 async
和 await
的能力形式 expressions ,我们可以以多种样式使用它们,包括功能样式。
We could write the same program using imperative style. Or we could write it functional style using .then
too. We can write it all sorts of ways and I guess that's the point – Thanks to async
and await
's ability to form expressions, we can use them in a variety of styles, including functional style.
在下面的浏览器中运行整个程序
Run the entire program in your browser below
const asyncUnfold = async (f, init) =>
f ( async (x, acc) => [ x, ...await asyncUnfold (f, acc) ]
, async () => []
, init
)
const Db =
{ getChildren : (id) =>
new Promise (r => setTimeout (r, 100, data [id] || []))
}
const Empty =
Symbol ()
const traverse = (id) =>
asyncUnfold
( async (next, done, [ id = Empty, ...rest ]) =>
id === Empty
? done ()
: next (id, [ ...await Db.getChildren (id), ...rest ])
, [ id ]
)
const data =
{ 0 : [ 1, 2, 3 ]
, 1 : [ 11, 12, 13 ]
, 2 : [ 21, 22, 23 ]
, 3 : [ 31, 32, 33 ]
, 11 : [ 111, 112, 113 ]
, 33 : [ 333 ]
, 333 : [ 3333 ]
}
traverse (0) .then (console.log, console.error)
// => Promise
// ~2 seconds later
// [ 0, 1, 11, 111, 112, 113, 12, 13, 2, 21, 22, 23, 3, 31, 32, 33, 333, 3333 ]
这篇关于如何取消这些承诺的嵌套?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!