js执行顺序

本篇随笔主要通过两个案例来梳理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 

 

学习资料

掘进翻译计划

 

posted @ 2019-04-28 16:53  wxh27  阅读(547)  评论(1编辑  收藏  举报