读笔试题——JavaScript事件循环机制(event loop、macrotask、microtask)有感
对于js事件循环机制,顶部那篇文章写的很好,但我认为例子对于初学者不是太直观,因此放出下面这个例子,如有哪些地方说的不对,敬请指出:
代码1
/* test.js */
for(let i = 0; i < 3; i++) {
setTimeout(_ => {
// 逐个推入 macrotasks 事件队列中
console.log(`timeout: ${i}`)
}, 0)
new Promise((resolve) => {
// new Promise中的语句立即执行
console.log(`promise: ${i}`)
resolve()
}).then(_ => {
// 逐个推入 microtasks 事件队列中,同一个 event loop 中,先于 macrotasks 执行
console.log(`promise.then: ${i}`)
})
// 立即执行
console.log(`immediate: ${i}`)
}
结果1
> node test.js
promise: 0
immediate: 0
promise: 1
immediate: 1
promise: 2
immediate: 2
then: 0
then: 1
then: 2
timeout: 0
timeout: 1
timeout: 2
还有一个例子,个人认为更加完整,但是代码比较繁琐比较丑,可以直接拉到底部看结果
代码2
/* test.js */
// utils
const PRE = {
macrotask : "macrotask ",
microtask : "microtask ",
promiseImmediate : "promiseImmediate ",
immediate : "immediate "
}
function setTimeoutLog(w, f) {
setTimeout(_ => {
console.log(`${PRE.macrotask}: ${w}`)
if(f instanceof Function) {
f(PRE.macrotask)
}
}, 0)
}
function promiseLog(w) {
return new Promise((resolve) => {
console.log(`${PRE.promiseImmediate}: ${w}`)
resolve(PRE.microtask)
})
}
function immediateLog(w) {
console.log(`${PRE.immediate}: ${w}`)
}
// main
for(let i = 0; i < 3; i++) {
setTimeoutLog(i, pre => {
setTimeoutLog(`${pre} -> ${PRE.macrotask} ${i}`)
promiseLog(`${pre} -> ${PRE.promiseImmediate} ${i}`)
})
promiseLog(i).then(pre => {
setTimeoutLog(`${pre} -> ${PRE.macrotask} ${i}`)
promiseLog(`${pre} -> ${PRE.promiseImmediate} ${i}`)
})
immediateLog(i)
}
结果2
> node test.js
promiseImmediate : 0
immediate : 0
promiseImmediate : 1
immediate : 1
promiseImmediate : 2
immediate : 2
# 进入了 microtask 队列
promiseImmediate : microtask -> promiseImmediate 0
promiseImmediate : microtask -> promiseImmediate 1
promiseImmediate : microtask -> promiseImmediate 2
# 进入了 macrotask 队列,按入列时的先后顺序依次执行队列
macrotask : 0
promiseImmediate : macrotask -> promiseImmediate 0
macrotask : 1
promiseImmediate : macrotask -> promiseImmediate 1
macrotask : 2
promiseImmediate : macrotask -> promiseImmediate 2
# microtask 执行时入列的 macrotask
macrotask : microtask -> macrotask 0
macrotask : microtask -> macrotask 1
macrotask : microtask -> macrotask 2
# macrotask 执行时入列的 macrotask
macrotask : macrotask -> macrotask 0
macrotask : macrotask -> macrotask 1
macrotask : macrotask -> macrotask 2
不得不吐槽掘金的草稿保存机制了,添加一个标签就触发一次缓存,这没问题,但是,缓存期间禁用发布按钮并关闭发布框,这就有点。。。人家SF做的就讲理点。