图解同步以及异步


去年写了一个同步和异步之前的差异其中说了事件循环,但是有点模糊,这里再记载一下
stack
从图中所知,js运行代码时会把任务放到main stack中,如图所示stack的特点是先进后出,后进先出
但是遇到异步代码会怎么样
event loop
如图所示,js引擎会优先执行同步代码,遇到异步代码会首先把异步代码通过web api挂载起来,他会把里面的代码加到一个队列中,队列的特性是先进先出后进后出,等异步代码执行完毕,再把里面的同步代码放入到main stack中运行

宏任务与微任务

当遇到异步任务时被加入到事件循环时,同时分为宏任务(macrotask)以及微任务(microtask)这两读音好像啊。

其中宏任务有

  • script全部代码
  • setTimeout
  • setInterval
  • setImmediate(浏览器暂时不支持,只有IE10支持,具体可见MDN)
  • I/O操作
  • UI Rendering

    微任务有

  • Promise.then
  • MutaionObserver
  • process.nextTick (Node.js)
  • Object.observe(废弃)

当js挂起异步任务的时候,其中有两个队列,一个是宏任务队列一个是微任务队列,其中是怎么运行的呢

  • 选择当前要执行的任务队列,选择任务队列中最先进入的任务,如果任务队列为空即null,则执行跳转到微任务(MicroTask)的执行步骤。
  • 将事件循环中的任务设置为已选择任务
  • 执行任务
  • 将事件循环中当前运行任务设置为null
  • 将已经运行完成的任务从任务队列中删除
  • microtasks步骤:进入microtask检查点
  • 更新界面渲染
  • 返回第一步

    运行流程如下,一句话总结来说:微任务权重比宏任务要高在队列中优先执行

练习题

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');  

首先执行同步代码console.log('script start');
然后挂起一个宏任务 console.log('setTimeout');
再执行同步代码 console.log('async1 start');
继续执行async2的同步代码console.log('async2');
挂起微任务console.log('async1 end');
下面的new Promise执行同步代码console.log('promise1');
.then挂起微任务console.log('promise2');
执行同步代码console.log('script end');
所以执行结果是

script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout

下面还有两题同理

setTimeout(() => {
    console.log('A'); // 4 
}, 0);
var obj = {
    func: function () {
        setTimeout(function () {
            console.log('B'); //5
        }, 0);
        return new Promise(function (resolve) {
            console.log('C'); // 1 
            resolve();
        });
    },
};
obj.func().then(function () {
    console.log('D'); // 3
});
console.log('E'); // 2 
let p = new Promise(resolve => {
    resolve(1);
    Promise.resolve().then(() => console.log(2)); 
    console.log(4);
}).then(t => console.log(t));
console.log(3);
Last modification:April 16, 2020
If you think my article is useful to you, please feel free to appreciate