EventLoop 即事件循环机制,是指浏览器或 Node 的一种解决 JavaScript 单线程运行时不会阻塞的一种机制,也就是我们经常使用异步的原理。
执行栈(Execution Context Stack)
。任务队列(Task Queue)
。只要异步任务有了运行结果,就在任务队列之中放置一个事件。执行栈
中的所有同步任务执行完毕,系统就会读取任务队列
,看看里面有哪些事件。如果有那些对应的异步任务
,于是结束等待状态,进入执行栈,开始执行。总结:调用栈中的同步任务都执行完毕,栈内被清空了,就代表主线程空闲了。 这个时候就会去任务队列中按照顺序读取一个任务放入到栈中执行。 每次栈内被清空,都会去读取任务队列有没有任务,有就读取执行,一直循环读取~执行的操作。
主线程从“任务队列”中读取执行事件,这个过程是循环不断的,这个机制被称为事件循环。此机制具体如下:
宏任务(MacroTask)
、微任务(MicroTask)
。setTimeout
、setInterval
、setImmediate
(浏览器暂时不支持,只有 IE10 支持,具体可见 MDN。)、I/O
、UI Rendering
。Process.nextTick
(Node独有)、Promise
、Object.observe(废弃)
、MutationObserver
(具体使用方式查看这里)JavaScript 单线程任务被分为同步任务和异步任务,同步任务会在调用栈中按照顺序等待主线程依次执行。异步任务会在异步任务有了结果后,将注册的回调函数放入任务队列中,等待主线程空闲的时候(调用栈被清空),被读取到栈内等待主线程的执行。
最先进入的微任务队列
的微任务,将事件循环的微任务设置为当前选择的微任务
。先入先出
的规则全部执行完 微任务 后,设置 微任务队列 为 null,然后再执行宏任务,如此循环。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');
script start
script end
promise1
promise2
setTimeout
Promise1
,执行完成 Promise1
后,调用 Promise2.then
,放入 微任务队列 中,再执行 Promise2.then
。setTimeout callback
,打印日志。setTimeout(function () {
console.log('timer1');
Promise.resolve()
.then(function () {
console.log('promise1');
});
});
setTimeout(function () {
console.log('timer2');
Promise.resolve()
.then(function () {
console.log('promise2');
});
});
// 例子
console.log('script start');
async function async1() {
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2 end');
}
async1();
setTimeout(function () {
console.log('setTimeout');
}, 0);
new Promise((resolve) => {
console.log('Promise');
resolve();
})
.then(function () {
console.log('promise1');
})
.then(function () {
console.log('promise2');
});
console.log('script end');
// 结果
script start
async2 end
Promise
script end
async1 end
promise1
promise2
setTimeout
// 只需将 async1 的执行理解为
function async1() {
return async2().then(() => {
console.log('async1 end');
});
}
Sorry, your browser does not support the video tag.
执行步骤如上所示
script start
。async2 end
,将 async2.then 放入微任务队列中。Promise
,将 Promise.then 放入微任务队列中。script end
async1 end
promise1
,并将 promise1.then 放入微任务队列中。promise2
setTimeout
console.log('script start');
async function async1() {
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2 end');
}
async1();
setTimeout(function () {
console.log('setTimeout1');
}, 100);
setTimeout(function () {
console.log('setTimeout2');
}, 10);
setTimeout(function () {
console.log('setTimeout3');
}, 0);
setTimeout(function () {
console.log('setTimeout4');
}, 0);
new Promise((resolve) => {
console.log('Promise');
setTimeout(function () {
console.log('Promise-setTimeout');
}, 10);
resolve();
})
.then(function () {
setTimeout(function () {
console.log('promise1-setTimeout');
}, 10);
console.log('promise1');
})
.then(function () {
setTimeout(function () {
console.log('promise2-setTimeout');
}, 0);
console.log('promise2');
});
console.log('script end');
先思考再查看答案哦~
运行结果
script start
async2 end
Promise
script end
async1 end
promise1
promise2
setTimeout3
setTimeout4
promise2-setTimeout
setTimeout2
Promise-setTimeout
promise1-setTimeout
setTimeout1
运行步骤
script start
。async2 end
,将 async2.then 放入微任务队列中。Promise
,将 Promise.then 放入微任务队列中,将 Promise-setTimeout 放入宏任务队列中。script end
async1 end
promise1
,并将 promise1.then 放入微任务队列中。promise2
。setTimeout3
setTimeout4
promise2-setTimeout
setTimeout2
Promise-setTimeout
promise1-setTimeout
setTimeout1