看过不少setTimeout、Promise执行顺序的面试题,一直不明白为啥都是异步操做,Promise就牛×些呢?直到了解了macrotask和micromask才恍然大悟...web
先来一道面试题助助兴:面试
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
咱们都知道JavaScript是一门单线程的语言,这也就意味着 JS 没法进行多线程编程,可是 JS 当中却有着无处不在的异步概念 。要彻底理解异步,就须要了解 JS 的运行核心——事件队列(Event Loop)。实际上,JS代码执行都处于事件循环里。事件循环发现有异步事件发生,就把这个任务放到事件队伍中。编程
事件队列是一个存储着待执行任务的队列,直白点说就是:咱们把每一次的异步操做(setTimeout、onclick、oninput事件、Promise...)当作一个异步任务,每进行一次异步操做,就把这个异步任务放入到异步事件的队列中,直到主线程任务执行完毕,而后开始异步的事件队列里的任务按顺序执行。多线程
Macrotasks和Microtasksapp
Macrotasks和Microtasks 都属于上述的异步任务中的一种,他们分别有以下API:异步
macrotasks: setTimeout, setInterval, setImmediate, I/O, UI renderingoop
microtasks: process.nextTick, Promise, MutationObserverpost
异步任务队列分为 macrotasks 和 microtasks, 在每一次事件循环中,macrotask只会提取一个执行,而microtask会一直提取,直到microsoft队列为空为止。也就是说若是某个microtask任务被推入到执行中,那么当主线程任务执行完成后,会循环调用该队列任务中的下一个任务来执行,直到该任务队列到最后一个任务为止(microtasks优于macrotasks执行)。而事件循环每次只会入栈一个macrotask,主线程执行完成该任务后又会检查microtasks队列并完成里面的全部任务后再执行macrotask的任务。ui
弄清楚了这条规则后,再来分析上面的面试题就小菜一碟了。 spa
参考文章: