js event Loop的机制

enent Loop 即时事件循环,在浏览器或者node环境下js单线程运行时不会阻塞的一种机制,也就是我们所理解的异步原理

js的运行机制是分为堆、栈和队列,如图所示:
在这里插入图片描述
而在js机制中,js是分为宏任务(MacroTask)也叫Task和微任务(MicroTask)的,浏览器在运行的时候会首先清空微任务,然后才会执行宏任务。

mask宏任务:
script全部代码、setTimeout、setInterval、setImmediate(浏览器暂时不支持,只有IE10支持,具体可见MDN)、I/O、UI Rendering

MicroTask微任务:
Process.nextTick(Node独有,vue里面有用)、Promise、Object.observe(废弃)、MutationObserver,详情可查看这里

举例如下

     console.log('script start');

        setTimeout(function () {
            console.log('setTimeout');
        }, 0);

        Promise.resolve().then(function () {
            console.log('promise1');
        }).then(function () {
            console.log('promise2');
        });
        console.log('script end');
        注意:setTimeout是宏任务,Promise是微任务(如果是new Promise则是宏任务)

第一次执行:
执行同步代码,将宏任务(Tasks)和微任务(Microtasks)划分到各自队列中。
log:script start、script end
第二次执行:
执行宏任务后,检测到微任务(Microtasks)队列中不为空,执行Promise1,执行完成Promise1后,调用Promise2.then,放入微任务(Microtasks)队列中,再执行Promise2.then。
log:script start、script end、promise1、promise2
第三次执行:
当微任务(Microtasks)队列中为空时,执行宏任务(Tasks),执行setTimeout callback,打印日志。
log:script start、script end、promise1、promise2、setTimeout

 console.log('script start')  //1

        async function async1() {
            await async2()
            console.log('async1 end') //5
        }
        async function async2() {
            console.log('async2 end') //2
        }
        async1()

        setTimeout(function () {
            console.log('setTimeout') //8
        }, 0)

        new Promise(resolve => {
            console.log('Promise') //3
            resolve()
        })
            .then(function () {
                console.log('promise1') //6
            })
            .then(function () {
                console.log('promise2') //7
            })

        console.log('script end')//4

首先,打印script start,调用async1()时,返回一个Promise,所以打印出来async2 end。
每个 await,会新产生一个promise,但这个过程本身是异步的,所以该await后面不会立即调用。
继续执行同步代码,打印Promise和script end,将then函数放入微任务队列中等待执行。
同步执行完成之后,检查微任务队列是否为null,然后按照先入先出规则,依次执行。
然后先执行打印promise1,此时then的回调函数返回undefinde,此时又有then的链式调用,又放入微任务队列中,再次打印promise2。
再回到await的位置执行返回的 Promise 的 resolve 函数,这又会把 resolve 丢到微任务队列中,打印async1 end。
当微任务队列为空时,执行宏任务,打印setTimeout。

Process.nextTick()(vue中就是使用这个来进行插队的)

let bar;

setTimeout(() => {
  console.log('setTimeout');
}, 0)

setImmediate(() => {
  console.log('setImmediate');
})
function someAsyncApiCall(callback) {
  process.nextTick(callback);
}

someAsyncApiCall(() => {
  console.log('bar', bar); // 1
});

bar = 1;

结果:
bar 1
setTimeout
setImmediate
首先执行
process.nextTick(callback);

发布了21 篇原创文章 · 获赞 4 · 访问量 2737

猜你喜欢

转载自blog.csdn.net/smallico/article/details/101979247