我们发现,我们的执行流程出现了很大问题:在 mount 阶段未完成的时候就执行了 flushCallbacks,先执行更新操作,这里的顺序错乱导致了后续问题。
我们可看下调用 flushCallbacks 的代码:
1 2 3 4 5 6 7 8 9 10 11 12
if (typeofPromise !== 'undefined' && isNative(Promise)) { var p = Promise.resolve(); microTimerFunc = 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); } }; }
这里 microTimerFunc 的 p.then,被同步执行了,也就是说,这里的微任务优先于当前事件循环的函数执行了(此时由于 mount 流程是同步的,mount 流程的相关函数理应在该事件循环中,优先于微任务执行)。
// Here we have async deferring wrappers using both microtasks and (macro) tasks. // In < 2.4 we used microtasks everywhere, but there are some scenarios where // microtasks have too high a priority and fire in between supposedly // sequential events (e.g. #4521, #6690) or even between bubbling of the same // event (#6566). However, using (macro) tasks everywhere also has subtle problems // when state is changed right before repaint (e.g. #6813, out-in transitions). // Here we use microtask by default, but expose a way to force (macro) task when // needed (e.g. in event handlers attached by v-on).