vue文件调用
1.eg
mounted(){
this.title = '开心图书'
this.$nextTick(()=>{
document.title = this.title
})
}
源码部分
调用$nextTick函数执行
Vue.prototype.$nextTick = function (fn) {
return nextTick(fn, this)
};
定义nextTick函数需要用到的变量
// 把$nextTick传入的函数push到callbacks
const callbacks = [];
// pending是否正在执行标记
let pending = false;
flushCallbacks函数作用是遍历每一个$nextTick函数并触发执行
function flushCallbacks() {
pending = false;
const copies = callbacks.slice(0);
callbacks.length = 0;
for (let i = 0; i < copies.length; i++) {
copies[i]();
}
}
$nextTick的延迟和等待dom更新后触发
直接调用flushCallbacks执行回调
$nextTick之所以能够等待dom更新一次并在下一次更新之前执行,这块巧妙使用EventLoop的队列:
Task Queue(宏任务):包括例如定时器
Microtask Queue(微任务):包括promise/MutationObserver/setImmediate等
EventLoop队列分为Task Queue(宏任务)和Microtask Queue(微任务),宏任务每执行完一个任务,在执行下一个宏任务的之前,会检查微任务是否有待执行的任务,如果有一并执行并清空,这时候页面重新渲染一次,然后接着执行下一次宏任务,微任务…
let timerFunc;
if (typeof Promise !== "undefined" && isNative(Promise)) {
const p = Promise.resolve();
timerFunc = () => {
p.then(flushCallbacks);
if (isIOS) setTimeout(noop);
};
isUsingMicroTask = true;
} else if (
!isIE &&
typeof MutationObserver !== "undefined" &&
(isNative(MutationObserver) ||
// PhantomJS and iOS 7.x
MutationObserver.toString() === "[object MutationObserverConstructor]")
) {
// Use MutationObserver where native Promise is not available,
// e.g. PhantomJS, iOS7, Android 4.4
// (#6466 MutationObserver is unreliable in IE11)
let counter = 1;
const observer = new MutationObserver(flushCallbacks);
const textNode = document.createTextNode(String(counter));
observer.observe(textNode, {
characterData: true,
});
timerFunc = () => {
counter = (counter + 1) % 2;
textNode.data = String(counter);
};
isUsingMicroTask = true;
} else if (typeof setImmediate !== "undefined" && isNative(setImmediate)) {
timerFunc = () => {
setImmediate(flushCallbacks);
};
} else {
// Fallback to setTimeout.
timerFunc = () => {
setTimeout(flushCallbacks, 0);
};
}
nextTick在使用中之所以有时候在回调内部是获取到最新dom更新但是页面还未渲染的原因就是因为EventLoop的运行机制
当然,以上代码中也包含环境兼容处理,可谓优雅降级方式:Promise > MutationObserver > setImmediate > setTimeout
nextTick(fn, this)直接调用这个方法执行
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;
// 异步执行callback任务执行
timerFunc();
}
// $flow-disable-line
if (!cb && typeof Promise !== "undefined") {
return new Promise((resolve) => {
_resolve = resolve;
});
}
}