vm.$nextTick
这个API的作用是将当前任务的回调压到下一次事件循环的队列中去。
function nextTick (cb, ctx) {
var _resolve;
callbacks.push(function () {
if (cb) {
try {
cb.call(ctx);
} catch (e) {
handleError(e, ctx, 'nextTick');
}
} else if (_resolve) {
_resolve(ctx);
}
});
if (!pending) {
pending = true;
timerFunc();
}
// $flow-disable-line
if (!cb && typeof Promise !== 'undefined') {
return new Promise(function (resolve) {
_resolve = resolve;
})
}
}
先来看以上nextTick的代码。
callbacks就是存放回调的一个数组。首先,先在callbacks回调数组里压入一个匿名函数,在这个匿名函数中,先去判断用户是否传入了回调,如果传入了回调,那么,使用call的方式执行这个回调函数。但如果用户没有传入回调,那么会去判断promise的成功状态的回调是否存在,如果存在就执行promise成功状态的回调。
pending标记用来判断,当前是否需要将回调数组添加到事件队列。
var p = Promise.resolve();
timerFunc = function () {
p.then(flushCallbacks);
// In problematic UIWebViews, Promise.then doesn't completely break, but
// it can get stuck in a weird state where callbacks are pushed into the
// microtask queue but the queue isn't being flushed, until the browser
// needs to do some other work, e.g. handle a timer. Therefore we can
// "force" the microtask queue to be flushed by adding an empty timer.
if (isIOS) { setTimeout(noop); }
};
function flushCallbacks () {
pending = false;
var copies = callbacks.slice(0);
callbacks.length = 0;
for (var i = 0; i < copies.length; i++) {
copies[i]();
}
}
再来看以上两段代码,显而易见,flushCallbacks用来清空回调数组,并执行一遍所有回调。同时,将pending标记为false。即这一轮的回调已经全部执行完,之后,可以再向微任务事件队列添加回调数组。所以timeFunc函数的作用就是刷新回调,并为下一次添加回调数组至微任务事件队列做好前提准备。
以上是我看懂的部分,总结一下,nextTick将回调序列压入到微任务队列在一轮事件循环内只能执行一次。具体的实现方式,就是打pending标记的思路。
针对最后一段代码为_resolve赋值成功时的回调,还没有理解作者的思路,以后懂了再写。