Open vaakian opened 4 years ago
new Promise传入的函数会立即执行。 同步任务完成->microTask->macroTask
console.log('a') // sync
let promise = new Promise((resolve) => {
console.log('b') // sync
setTimeout(() => console.log('e'), 0) // macroTask
resolve()
})
promise.then(() => console.log('c')).then(() => console.log('f')) // microTask
console.log('d') // sync
结果是先执行同步任务abd
,然后微任务 cf
,最后宏任务e
macrotasks: setTimeout, setInterval, setImmediate, I/O, UI rendering microtasks: process.nextTick, Promise, MutationObserver
同步任务同其他语言一样,拥有调用栈。 当同步任务执行栈空时,JS将microTask队列中的任务依次压入调用栈并执行。 当microTask队列空时,JS将macroTask队列中的任务依次压入调用栈并执行。
先执行完所有同步任务,再检查执行完所有microTask,再挨个执行macroTask
分析题目
1、首先 setTimeout A 被加入到事件队列中 ==> 此时macrotasks中有[‘A’];
2、obj.func()执行时,setTimeout B 被加入到事件队列中 ==> 此时macrotasks中有[‘A’,‘B’];
3、接着return一个Promise对象,Promise 新建后立即执行 执行console.log('C'); 控制台首次打印‘C’;
4、然后,then方法指定的回调函数,被加入到microtasks队列,将在当前脚本所有同步任务执行完才会执行。 ==> 此时microtasks中有[‘D’];
5、然后继续执行当前脚本的同步任务,故控制台第二次输出‘E’;
6、此时所有同步任务执行完毕,如上所述先检查microtasks队列,完成其中所有任务,故控制台第三次输出‘D’;
7、最后再执行macrotask的任务,并且按照入队列的时间顺序,控制台第四次输出‘A’,控制台第五次输出‘B’。
浏览器render queue重绘优先级
当调用栈有任务时,不会执行重绘。 当事件循环队列有任务时,每执行完一个事件,有一次重绘机会,相当于event queue和render qeue交替执行。
所以如果任务时间开销很大,一定不能放在调用栈里,会阻塞浏览器重绘。