乐趣区

vue的nextTick原理解析

nextTick 在 vue 官方解释是说在下次 DOM 更新循环结束后立即执行延迟回调,获取更新后的 DOM

对于 microtasks(微任务)和 macrotasks(宏任务),vue 在 2.4 版本之前一直用 microtasks,但是它的优先级太高,在某些情况下可能会出现逼时间冒泡更快执行的情况;如果全部使用 macrotasks,对于大数据 DOM 会出现渲染性能问题。所以在新版本中 (vue 版本超过 2.4) 默认使用 microtasks,在特殊情况下会使用 macrotask,比如在使用 v -on 绑定事件。

对于使用 macrotasks,会先判断是否使用 setImmediate,不能的话降级为 MessageChannel,以上都不行,则使用 setTimeout

if(typeof setImmediate !== 'undefined' && isNative(setImmediate)) {macroTimerFunc = () => {setImmediate(flushCallbacks);
    };
} else if(typeof MessageChaanel !== 'undefined' && (isNative(MessageChaanel) || MessageChaanel.toString() === '[object MessageChannelConstructor]')) {const channel = new MessageChannel();
    const port = channel.port2;
    channel.port1.onmessage = flushCallbacks;
    macroTimerFunc = () => {port.postMessage(1);
    };
} else {macroTimerFunc = () => {setTimeout(flushCallbacks, 0);
    }
}

同时 nextTick 也支持 Promise

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)
        }
    })
    if(!pending) {
        pending = true;
        if(useMacroTask) {macroTimerFunc()
        } else {microTimerFunc()
        }
    }
    if(!cb && typeof Promise !== 'undefined') {
        return new Promise(resolve => {_resolve = resolve})
    }
}
退出移动版