看来看一段代码:
console.log('start');
setTimeout(function() {
console.log('settimeout1');
}, 0);
setTimeout(function() {
console.log('settimeout2');
Promise.resolve()
.then(function() {
console.log('Promise3');
})
.then(function() {
console.log('Promise4');
})
}, 0);
Promise.resolve()
.then(function() {
console.log('Promise1');
})
.then(function() {
console.log('Promise2');
})
我们知道,js的的执行机制是事件队列,即task queue,所有异步的操作都会放到下一个task queue中,不管是游览器还是node。但通过运行上面代码,似乎发现不同的异步事件放入task queue中有先后顺序。
没错,不同的异步任务也有所不同:
- macrotasks: setTimeout setInterval setImmediate I/O UI渲染
- microtasks: Promise process.nextTick Object.observe MutationObserver
每一个事件队列中包含macrotasks和microtasks,每一个task queue都从一个macrotasks开始执行,然后执行放入这个queue中的所有microtasks,大致如下:
![](https://img.haomeiwen.com/i3937628/f994eb259d531656.png)
可以看出
task queue == macrotask queue != microtask queue
所以照此来分析上面代码,不难得到答案,
任务队列1:
console.log('start');
Promise.resolve()
.then(function() {
console.log('Promise1');
})
.then(function() {
console.log('Promise2');
})
执行完macrotasks,再把队列的microtasks都执行完。
任务队列2:
setTimeout(function() {
console.log('settimeout1');
}, 0);
任务队列3
setTimeout(function() {
console.log('settimeout2');
Promise.resolve()
.then(function() {
console.log('Promise3');
})
.then(function() {
console.log('Promise4');
})
}, 0);
执行完settimeout2执行Promise3,Promise4。
最后输出:
start
Promise1
Promise2
settimeout1
settimeout2
Promise3
Promise4
macrotasks和microtasks最大的不同的是:当 macrotasks 出队时,任务是一个一个执行的;而microtasks 出队时,任务是一队一队执行的。也就是说microtasks的队列一次一定会执行完,利用这个特性,很多框架实现了批量更新render,比如vue的nextTick,查看源码
export function nextTick (cb?: Function, ctx?: Object) {
let _resolve
callbacks.push(() => {
if (cb) {
try {
cb.call(ctx)
} catch (e) {
handleError(e, ctx, 'nextTick')
}
} else if (_resolve) {
_resolve(ctx)
}
})
// 检查上一个异步任务队列(即名为callbacks的任务数组)是否派发和执行完毕了。pending此处相当于一个锁
if (!pending) {
// 若上一个异步任务队列已经执行完毕,则将pending设定为true(把锁锁上)
pending = true
// 是否要求一定要派发为macro任务
if (useMacroTask) {
macroTimerFunc()
} else {
// 如果不说明一定要macro 你们就全都是micro
microTimerFunc()
}
}
// $flow-disable-line
if (!cb && typeof Promise !== 'undefined') {
return new Promise(resolve => {
_resolve = resolve
})
}
}
可以看到,利用promise来包装成microtasks,将改变批量执行完。
网友评论