JavaScript入坑系列-1-EventLoop

206 阅读2分钟

参考资料

EventLoop

事件队列分为 TaskQueue(宏任务队列) 和 MicrotaskQueue(微任务队列)两种。

事件队列分类

  • TaskQueue:script标签引入的js代码,setTimeout,setInterval,IO,渲染...
  • MicrotaskQueue:Promise、async/await...

事件循环执行

当执行栈中的任务清空,开始一次事件循环。
主线程会从 TaskQueue 取出一个Task执行。
然后检查MicrotaskQueue中是否有Task,如果有,清空当前MicrotaskQueue队列。
一次事件循环结束。
然后开始看执行栈是否为空,当为空时,开始下一次事件循环。不为空时,清空执行栈,然后开始下一次事件循环。

本次事件循环添加的MicrotaskQueue和TaskQueue,MicrotaskQueue在本次事件循环结束会被执行,TaskQueue 会在后续的事件循环中去执行

Demo

Demo1

    <body>
        测试事件循环机制
        <div id="outer" class="outer">
            <div id="inner" class="inner"></div>
        </div>
        <script src="./app1.js"></script>
        <script src="./app2.js"></script>
    </body>
// app1.js
console.log('app1.js 开始');
setTimeout(() => {
    console.log('app1.js-setTimeout 2000ms 执行');
}, 20);
setTimeout(() => {
    console.log('app1.js-setTimeout 1000ms 执行');
}, 10);
Promise.resolve().then(() => {
    console.log('Promise.resolve()');
});
const promise1 = new Promise((resolve, reject) => {
    console.log('app1.js-promise1 -init');
    resolve('app1.js-promise1');
});
const promise2 = new Promise((resolve, reject) => {
    console.log('app1.js-promise2 -init');
    resolve('app1.js-promise2');
}).then(data => {
    console.log('app1.js-promise2 第一次 then');
    return data;
});
promise1
    .then(data => {
        console.log('app1.js-promise1 第一次 then');
        return data;
    })
    .then(data => console.log(`app1.js-promise1 第二次 then--${data}`))
    .then(data => console.log(`app1.js-promise1 第三次 then--${data}`))
    .then(data => console.log(`app1.js-promise1 第四次 then--${data}`));
promise2.then(data => console.log(`app1.js-promise2 第二次 then--${data}`)).then(data => console.log(`app1.js-promise2 第三次 then--${data}`));
console.log('app1.js 结束');
// app2.js
console.log('app2.js 开始');
setTimeout(() => {
    console.log('app2.js-setTimeout 2000ms 执行');
}, 20);
setTimeout(() => {
    console.log('app2.js-setTimeout 1000ms 执行');
}, 10);
const promise3 = new Promise((resolve, reject) => {
    console.log('app2.js-promise1 -init');
    resolve('app2.js-promise1');
}).then(data => {
    console.log('app2.js-promise1 第一次 then');
    return data;
});
const promise4 = new Promise((resolve, reject) => {
    console.log('app2.js-promise2 -init');
    resolve('app2.js-promise2');
}).then(data => {
    console.log('app2.js-promise2 第一次 then');
    return data;
});
promise3
    .then(data => console.log(`app2.js-promise1 第二次 then--${data}`))
    .then(data => console.log(`app2.js-promise1 第三次 then--${data}`))
    .then(data => console.log(`app2.js-promise1 第四次 then--${data}`));
promise4.then(data => console.log(`app2.js-promise2 第二次 then--${data}`)).then(data => console.log(`app2.js-promise2 第三次 then--${data}`));
console.log('app2.js 结束');

运行结果

// 主线程运行的执行栈代码
app1.js 开始
app1.js:12 app1.js-promise1 -init
app1.js:16 app1.js-promise2 -init
app1.js:31 app1.js 结束

// 执行栈清空,清空 MicrotaskQueue
app1.js:9 Promise.resolve()
app1.js:19 app1.js-promise2 第一次 then
app1.js:24 app1.js-promise1 第一次 then
app1.js:30 app1.js-promise2 第二次 then--app1.js-promise2
app1.js:27 app1.js-promise1 第二次 then--app1.js-promise1
app1.js:30 app1.js-promise2 第三次 then--undefined
app1.js:28 app1.js-promise1 第三次 then--undefined
app1.js:29 app1.js-promise1 第四次 then--undefined

// 执行栈没有可执行的,开始新一轮的事件循环,执行 MicrotaskQueue, 
// MicrotaskQueue没有task,所以执行setTimeout
app1.js:6 app1.js-setTimeout 1000ms 执行

// 执行栈没有可执行的,开始新一轮的事件循环,执行 MicrotaskQueue, 
// MicrotaskQueue没有task,所以执行setTimeout
app1.js:3 app1.js-setTimeout 2000ms 执行

// 执行栈没有可执行的,开始新一轮的事件循环,执行 MicrotaskQueue, 
// MicrotaskQueue没有task,所以执行script 标签引入 app2.js 代码
app2.js:1 app2.js 开始
app2.js:9 app2.js-promise1 -init
app2.js:16 app2.js-promise2 -init
app2.js:27 app2.js 结束

app2.js:12 app2.js-promise1 第一次 then
app2.js:19 app2.js-promise2 第一次 then
app2.js:23 app2.js-promise1 第二次 then--app2.js-promise1
app2.js:26 app2.js-promise2 第二次 then--app2.js-promise2
app2.js:24 app2.js-promise1 第三次 then--undefined
app2.js:26 app2.js-promise2 第三次 then--undefined
app2.js:25 app2.js-promise1 第四次 then--undefined

app2.js:6 app2.js-setTimeout 1000ms 执行
app2.js:3 app2.js-setTimeout 2000ms 执行