ECMAScript-2017,大约在一个月前完成,它引入了'asynchronous functions'作为新功能。为了了解它们是如何“异步”的,我在Chrome中进行了一项测试:
async function af1(){
for (let i=0; i<300; i++)
await (new Promise(
(resolve,reject)=>{
for (let j=0; j<=4; j++) console.log(j);resolve();}))
.then(()=>{for (let j=100; j<=400; j+=100) console.log(j);});;
}
async function af2(){
for (let i=0; i<300; i++)
await (new Promise(
(resolve,reject)=>{
for (let j=5; j<=9; j++) console.log(j);resolve();}))
.then(()=>{for (let j=500; j<=900; j+=100) console.log(j);});
}
af1();
console.log(300);
af2();
console.log(400);
// 0 1 2 3 4 300 5 6 7 8 9 400 100 200 300 400 500 600 700 800 900
// 0 1 2 3 4 5 6 7 8 9 100 200 300 400 500 600 700 800 900
// 0 1 2 3 4 5 6 7 8 9 100 200 300 400 500 600 700 800 900
// 0 1 2 3 4 5 6 7 8 9 100 200 300 400 500 600 700 800 900
// 0 1 2 3 4 5 6 7 8 9 100 200 300 400 500 600 700 800 900
// 0 1 2 3 4 5 6 7 8 9 100 200 300 400 500 600 700 800 900
// ......
实际上我期待一个更随机的序列。
现在,我可以有把握地说,代表一个promise或其then()回调的每个代码块都是原子的,因为块内代码的执行不能被代码中的另一部分代码中断。同样的计划?
答案 0 :(得分:4)
编写异步代码并不意味着输出是随机的。当承诺立即得到解决(而不是依赖于一些不受控制的外部事件),那么事件序列实际上是可预测的:
在Promise构造函数回调函数中执行的所有内容都将在创建promise时执行,即它在继续new Promise()
之后的代码之前同步运行。
然后执行其余的同步代码,直到调用堆栈为空。
然后,作为附加到当前任务的微任务的一部分,将按先前执行then
方法的顺序执行异步then
回调。
await
关键字也会影响执行顺序:它们发生的async
函数将&#34;停止&#34;,让调用代码同步继续,就好像{{ 1}}函数执行了async
(它返回一个promise)。一旦提供给return
的承诺得到解决,await
函数将异步恢复其状态(在当前执行代码运行之后直到调用堆栈为空),并继续作为微任务的一部分。此时间与async
回调相同。
这解释了你的输出。没有随机性。
比如,在第一行输出结束时,900,是什么表示执行回到
then
?
在输出900时,队列中有两个待处理的微任务:
1)af1()
中的then
回调已完成执行,返回值af1
(因为它没有undefined
),这表示承诺的值return
正在等待。这是等待异步处理,而当前代码仍在运行,直到调用堆栈为空。
2)await
中的then
回调也已完成执行:原则相同。
由于(1)在微任务队列中是第一个,这是在输出900之后发生的事情,并且没有更多的同步代码要执行(调用堆栈是空的):
JavaScript引擎读取微任务队列并使用微任务处理第一个af2
:恢复功能状态,包括其循环状态,并继续循环。这意味着promise构造函数回调是同步执行的,产生输出第二行中的第一个值。 ...等