Promise
Promise新建后会立即执行,then方法指定的回调函数在当前脚本的所有同步任务执行完时执行
setTimeout
setTimeout(function() {
console.log('B');
}, 0);
第二个参数设为0只是把函数放入异步队列,浏览器执行完同步队列中的任务才去执行异步队列中的任务,所以A,B处于异步队列中最后才被执行
关于异步任务队列
Macrotasks(task queue)和Microtasks 都属于异步任务中的一种,他们分别有如下API:
macrotasks: setTimeout, setInterval, setImmediate, I/O, UI rendering
microtasks: process.nextTick, Promise, MutationObserver
Promise的函数代码的异步任务会优先于setTimeout的延时为0的任务先执行。因为任务队列分为 macrotasks 和 microtasks, 而promise中的then方法的函数会被推入到microtasks队列中,而setTimeout函数会被推入到macrotasks
事件循环的执行过程
开始 -> 取macrotasks的一个任务(task)执行-> 取microtask全部任务依次执行 -> 取macrotasks下一个任务执行 -> 再次取出microtask全部任务执行 -> ... 这样循环往复
注:macrotask的前一个task的回调函数会在下一个task开头执行,即在前一趟的microtask之后执行
setTimeout(() => {
console.log('A');
}, 0);
var obj = {
func: function() {
setTimeout(function() {
console.log('B');
}, 0);
return new Promise(function(resolve) {
console.log('C');
resolve();
});
}
};
obj.func().then(function() {
console.log('D');
});
console.log('E');
//输出结果如下
//C
//E
//D
//A
//B
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’。
解释来源:https://www.qdskill.com/javascript/8429.html