直接上代码
const callbacks = [] // 任务队列
let pending = false
function flushCallbacks() {
pending = false
const copies = callbacks.slice(0)
callbacks.length=0 // 清空队列
for(let i =0,l=copies.length;i<l;i++){
copies[i]() // 执行所有任务
}
}
let microTimerFunc // 默认注册微任务
let macroTimerFunc // 注册二级宏任务
let useMacroTask = false
// 微任务注册函数(Promise.then)
if(typeof Promise !=='undefined'){
microTimerFunc = ()=>{
Promise.resolve().then(flushCallbacks)
}
}else{
microTimerFunc = macroTimerFunc // 浏览器不支持Promise只能注册二级宏任务
}
// 二级宏任务注册函数(setImmediate -> MessageChannel -> setTimeout)
if(typeof setImmediate !=='undefined'){
macroTimerFunc = ()=>{
setImmediate(flushCallbacks)
}
}
else if(
typeof MessageChannel !=='undefined'
&&MessageChannel.toString()==='[object MessageChannelConstructor]'
){
const channel = new MessageChannel()
const port1 = channel.port1
const port2 = channel.port2
port1.onmessage = flushCallbacks
macroTimerFunc= ()=>{
port2.postMessage(1)
}
}
else{
macroTimerFunc = ()=>{
setTimeout(flushCallbacks,0)
}
}
// 设置外层函数调用nextTick时注册二级宏任务
function withMacroTask(fn) {
return fn._withTask||(fn._withTask=function () {
useMacroTask = true
const res = fn.apply(null,arguments)
useMacroTask = false
return res
})
}
function nextTick(cb,ctx) {
let _resolve
callbacks.push(()=>{
if(cb){
cb.call(ctx)
}else if(_resolve){ // this.$nextTick().then(()=>{...})
_resolve(ctx)
}
})
if(!pending){
pending = true
if (useMacroTask) {
macroTimerFunc()
}else{
microTimerFunc()
}
}
if(!cb&&typeof Promise !=='undefined'){
return new Promise(resolve=>{
_resolve = resolve
})
}
}
// 测试
nextTick(function(){console.log(this.name)},{name:2})
setTimeout(()=>{console.log(4)})
nextTick().then(()=>{console.log(5)})
console.log(1)
nextTick(()=>{console.log(this.name)},{name:3})
// 1 2 3 5 4