本篇随笔主要通过两个案例来梳理promise执行顺序和promise、async/await执行顺序,介绍之前默认大家已经了解这两个api的使用方法并且了解js宏任务与微任务概念。文章末尾会附上相关资料,有兴趣的可以查看。
一、promise
console.log(‘script start‘);setTimeout(function() { ?console.log(‘setTimeout‘);}, 0);Promise.resolve().then(function() { ?console.log(‘promise1‘);}).then(function() { ?console.log(‘promise2‘);});console.log(‘script end‘);
大概看几眼,直接上答案和分析:script start、script end、promise1、promise2、setTimeout;
开始分析:
1、第一个输出大家都没问题,代码执行到第二行遇到setTimeout,js引擎把定时器回调函数当做一个宏任务放入回调队列(callback queue),让出js主线程继续往下执行;
2、到第五行是个promise.resolve()异步执行函数(微任务),所以js引擎把then后面的回调函数放入当前调用栈末尾,让出js主线程继续往下执行。
3、执行完最后一行,输出script end;此时at the end of a task,we process microtasks(当前宏任务执行完毕,开始执行微任务,也就是第2步中的),输出promise1,接着继续往下执行,又遇到了promise回调函数,所以也把第二个then后面的回调函数当成微任务放入当前调用栈末尾。
4、因为当前调用栈中的微任务必须先于下一个宏任务执行,所以继续执行第3步中的微任务,输出promise2。
5、当前调用栈中代码全部执行完,根据事件循环机制,js引擎将回调队列中宏任务放入调用栈中执行,输出setTimeout。
二、promise、async/await
async function async1(){ ???console.log(‘async1 start‘) ???await async2() ???console.log(‘async1 end‘)}async function async2(){ ???console.log(‘async2‘)}console.log(‘script start‘)setTimeout(function(){ ???console.log(‘setTimeout‘) },0) ?async1();new Promise(function(resolve){ ???console.log(‘promise1‘) ???resolve();}).then(function(){ ???console.log(‘promise2‘)})console.log(‘script end‘)
最后输出:
script start
async start
async2
promise1
script end
promise2
async1 end
setTimeout
分析:
1、首先输出script start,然后将setTimeout的回调函数当成一个宏任务放入回调队列,让出js主线程,执行async1()。虽然async1是用async声明的异步函数,但是他本身依旧是一个立即执行函数,所以进入async1,执行输出async start。
2、直到遇到了await(async wait的缩写)这个熊孩子,看js是怎么处理他的。遇到await之后,js会执行完他后面的表达式/函数,然后跳出这个异步函数。这里呢,await后面跟的用async声明的async2异步函数,所以执行完,await后面是一个promise对象(未resolve),跳出async1。
3、执行到new promise,立即输出promise1,然后是他的resolve(),所以暂停执行,把promise的回调函数当成一个微任务放到当前调用栈末尾,跳出promise,执行最后一行,输出script end。
4、注意注意,下面的不好理解。接着执行第2步中的async1,此时await后面的promise开始resolve,所以js将async2函数的返回值(promise对象)的回调函数当做一个微任务,放到当前调用栈末尾,js主线程又让出async1函数。
5、此时当前调用栈中宏任务执行完毕,立即按顺序执行微任务。也就是第3步中的,直接输出promise2。接着执行第4步中产生的微任务(当然,没有执行任何东西),这会之后,js才正式通过await那一行,输出async1 end。这就是为什么promie2先于async1 end 输出。
6、扫扫尾,js执行下一个宏任务,输出setTimeout,到此全部结束。
上面的我加粗的那两个输出内容,是大家最疑惑的地方,也是最不好理解的地方,希望大家可以好好解读一下我的分析。
手敲不易,如果对你来说有一点帮助,请献出你们的免费推荐。下面是一些我参考的资料和一个学习资料。
async/await编码的技巧
promise、async和await之执行顺序的那点事
Tasks, microtasks, queues and schedules
Tasks, microtasks, queues and schedules(翻译)
理解js中的async/await
学习资料
掘进翻译计划
js执行顺序
原文地址:https://www.cnblogs.com/js123/p/10775170.html