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');<br><br><br>//打印结果
打印结果:
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]