import { noop } from 'shared/util' import { handleError } from './error' import { isIOS, isNative } from './env' // 存储nextTick需要执行的回调; const callbacks = []; // 当前回调是否在执行中; let pending = false; // 执行callbacks回调; function flushCallbacks () { pending = false const copies = callbacks.slice(0) callbacks.length = 0 for (let i = 0; i < copies.length; i++) { copies[i]() } } // nextTick做微任务执行时的包装函数 let microTimerFunc // nextTick做宏任务执行时的包装函数 let macroTimerFunc // nextTick按宏任务还是微任务执行 let useMacroTask = false // macroTimerFunc赋值,优先级 setImmediate | postMessage | setTimeout if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) { macroTimerFunc = () => { setImmediate(flushCallbacks) } } else if (typeof MessageChannel !== 'undefined' && ( isNative(MessageChannel) || // PhantomJS MessageChannel.toString() === '[object MessageChannelConstructor]' )) { const channel = new MessageChannel() const port = channel.port2 channel.port1.onmessage = flushCallbacks macroTimerFunc = () => { port.postMessage(1) } } else { /* istanbul ignore next */ macroTimerFunc = () => { setTimeout(flushCallbacks, 0) } } // microTimerFunc赋值,promise | setTimeout if (typeof Promise !== 'undefined' && isNative(Promise)) { const p = Promise.resolve() microTimerFunc = () => { p.then(flushCallbacks) if (isIOS) setTimeout(noop) } } else { // fallback to macro microTimerFunc = macroTimerFunc } // 函数执行过程中,如果有其他事件插入,会强制走MacroTask;否则,会走MicroTask export function withMacroTask (fn: Function): Function { return fn._withTask || (fn._withTask = function () { useMacroTask = true const res = fn.apply(null, arguments) useMacroTask = false return res }) } export function nextTick (cb?: Function, ctx?: Object) { let _resolve // push回调 callbacks.push(() => { if (cb) { try { cb.call(ctx) } catch (e) { handleError(e, ctx, 'nextTick') } } else if (_resolve) { _resolve(ctx) } }) if (!pending) { pending = true // 按微任务还是宏任务执行,默认微 if (useMacroTask) { macroTimerFunc() } else { microTimerFunc() } } // $flow-disable-line if (!cb && typeof Promise !== 'undefined') { return new Promise(resolve => { _resolve = resolve }) } }