setTimeout 、 promise、async await 的执行顺序?宏任务、微任务,分别包含哪些?
JS 分为同步任务和异步任务
同步任务在主线程上执行
异步任务放在主线程之外的一个任务队列
主线程执行完毕后,读取任务队列的内容
宏任务(macro)task:当前主线程上执行的就是一个宏任务。例: script 的代码、setTimeout、setInterval、postMessage等。
微任务:microtask。例:Promise.then、await后面的代码。
在执行当前宏任务时(同步执行时),遇到 setTimeout 会把它放到宏任务队列。遇到Promise.then会放到微任务队列。
当前 宏任务 执行完毕后,会先查看微任务队列,如果有任务,优先执行,否则执行下一个宏任务。所以 promise.then 会先于 setTimeout执行。
试试这段代码(头条):
//请写出输出内容 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 async1 start async2 promise1 script end async1 end promise2 setTimeout */
根据上面的原则来,基本没啥问题了。但是肯定有个疑惑的地方。为什么 “async1 end” 跑到了倒数第三个。
那是因为 async 函数中,遇到 await 会跳出当前函数,并让出线程,再将await后面的代码放到 微任务(microtask)队列中。
整个执行过程:
1、同步执行, 输出“script start”。
2、遇到setTimeout,将里面代码放到宏任务队列。
3、继续往下,输出 “async1 start”,然后执行 async2函数,输出 “async2”。
4、async2执行完毕,将await async2 后面的代码加入到 微任务队列;
5、继续执行,new Promise, 同步输出“promise1”。
6、遇到 promise.then,加入到微任务队列,
7、然后输出 "script end"。
8、当前宏任务执行完毕,查看微任务队列,按照先进先出原则。
9、依次输出“async1 end”、“promise2”
10、执行下一个宏任务,里面只有一个setTimeout,所以最后输出 “setTimeout”
同步执行的:[script start] [async1 start] [async2] [promise1] [script end]
微任务队列:[async1 end] [ promise2 ]
宏任务队列:[setTimeout]