Javascript 为什么我的异步函数要在实现之前执行?
我编写了一个小程序,比较了Javascript 为什么我的异步函数要在实现之前执行?,javascript,Javascript,我编写了一个小程序,比较了.then()方法和async/await方法的承诺履行情况。代码运行正常,但输出是按意外顺序接收的。有人能解释一下为什么输出是按当前顺序的吗 const backend=(num)=>{ const someVar=新承诺((解决、拒绝)=>{ 如果(数值%2==0){ 解析(`数字${num}是偶数。`); }否则{ 拒绝(`数字${num}是奇数。`); } }) 返回someVar; } 常量内置函数=(num)=>{ 后端(num) .then(messag
.then()
方法和async/await
方法的承诺履行情况。代码运行正常,但输出是按意外顺序接收的。有人能解释一下为什么输出是按当前顺序的吗
const backend=(num)=>{
const someVar=新承诺((解决、拒绝)=>{
如果(数值%2==0){
解析(`数字${num}是偶数。`);
}否则{
拒绝(`数字${num}是奇数。`);
}
})
返回someVar;
}
常量内置函数=(num)=>{
后端(num)
.then(message=>console.log(message))
.catch(message=>console.log(message));
}
常量AsyncWait=async(num)=>{
试一试{
const response=等待后端(num);
控制台日志(响应);
}捕获(错误){
console.log(错误);
}
}
内置式(2);
内置式(3);
异步等待(4);
异步等待(5)代码>对于微任务解析,每个方法调用都单独排队。所以执行的顺序是:
- 第一次呼叫排队
- 第二次呼叫排队
- 第三次呼叫排队
- 第四次呼叫排队
- 首先
。然后激发,console.logged
- 第二个
。然后
激发、拒绝、。捕获
处理程序排队(未调用)
- 异步/等待调用,console.logged
- 第二次调用async/await、rejection、catch块排队
.catch
解析,console.logged
- catch块解析为最终日志
在关于切换捕获顺序的评论中,向巴尔马提供道具
为了简单地说明(明显地),考虑一个计数器和一个允诺函数,它递增并递减它:
let i = 0;
const log = Promise.resolve()
.then(() => console.log(++i))
.then(() => console.log(--i));
log();
log();
这将打印1 2 1 0而不是1 0 1 0。如果你仔细想想,这是有一定意义的:方法链在任何一步都可能失败,因此运行时会将第一个调用和第二个排队。然后只在第一个调用完成后才会排队。否则,如果第一个调用失败(被拒绝),它将不得不返回并从回调队列中删除推测性排队的第二个调用。在得到答案之前,值得一提的是,依赖异步调用的执行顺序不是一个好的做法。有两种方法可以实现您的预期行为。首选方法应为:
(async() => {
await builtInFuncs(2);
await builtInFuncs(3);
await asyncAwait(4);
await asyncAwait(5);
})();
或者,您可以依赖ECMAScript标准保证的PromiseReactionJobs的执行顺序。您需要将内置函数重新定义为:
const builtInFuncs = (num) => {
backend(num).then(
message => console.log(message),
message => console.log(message)
);
}
请注意,onCompleted和onRejected处理程序都传递给.then()函数
观察到的执行顺序的实际原因相当复杂,但发生的情况如下:
内置函数(2)
被调用
内置函数(2)
调用后端(2)。然后()
backend(2).then()
实际上是排队console.log(2)
后端(2)。然后()
backend(2).then().catch()
注意到promise1
对象上的onRejected
处理程序
内置函数(3)
被调用
内置函数(3)
调用后端(3)。然后()
后端(3)。然后()
将一个虚拟onRejected
处理程序排入队列,因为未指定任何处理程序
后端(3)。然后()
后端(3).then().catch()
注意到调用
console.log(3)
onpromise2
asyncwait(4)
被调用
asyncwait(4)
有效地调用后端(4)。然后()
后端(4)。然后()
将继续执行try分支的oncompleted处理程序排入队列
asyncwait(5)
被调用
asyncwait(5)
有效地调用后端(5)。然后()
后端(5)。然后()
将继续捕获分支的onRejected处理程序排入队列
打印console.log(2)
的处理程序将退出队列
dummyonRejected
处理程序退出队列
promise2
enqueuesonRejected
handler它注意到哪个处理程序打印了console.log(3)
继续try分支的onCompleted处理程序已退出队列
继续捕获分支的onRejected处理程序已退出队列
打印console.log(3)
的处理程序将退出队列
请注意,后端
返回的承诺将立即得到解决或拒绝。如果没有,则会涉及更多步骤,但实际上会观察到相同的行为。我怀疑解决方案在事件队列中的优先级高于拒绝。您可以通过将顺序切换为:.catch(…)。然后(…)
但无法以类似方式重新排序try/catch
。@Barmar我根据您的建议更新了一个示例。@JaredSmith我认为try-and-catch的catch块不会排队。当const response=wait backend(num)时;catch块将运行,因为它不是对异步函数的调用,而是等待返回(已解析或已拒绝)的同步代码块。这就是为什么输出是2,4,5,3,而不是2,4,3,5。@MostafaAmin不,async/await不阻塞,它只是糖加于人的承诺。您可以通过同时运行多个异步调用来测试这一点。