此题属于原理题目,能够体现面试者对vue理解深度,答好了会加分很多。
vue有个批量、异步更新策略,数据变化时,vue开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次。然后在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。Vue 在内部对异步队列尝试使用原生的 Promise.then、MutationObserver 和 setImmediate,如果执行环境不支持,则会采用 setTimeout(fn, 0) 代替。
源码中,修改一个数据,组件对应的watcher会尝试入队:
queue.push(watcher)
并使用nextTick方法添加一个flushSchedulerQueue回调
nextTick(flushSchedulerQueue)
flushSchedulerQueue被加入callbacks数组
callbacks.push(() => { if (cb) { try { cb.call(ctx) // cb就是加入的回调 } catch (e) { handleError(e, ctx, 'nextTick') } } })
然后以异步方式启动
if (!pending) { pending = true timerFunc() }
timerFunc的异步主要利用Promise等微任务方式实现
let timerFunc if (typeof Promise !== 'undefined' && isNative(Promise)) { const p = Promise.resolve() // timerFunc利用p.then向微任务队列添加一个flushCallbacks // 会异步调用flushCallbacks timerFunc = () => { p.then(flushCallbacks) } isUsingMicroTask = true }
flushCallbacks遍历callbacks,执行里面所有回调
function flushCallbacks () { pending = false const copies = callbacks.slice(0) callbacks.length = 0 for (let i = 0; i < copies.length; i++) { copies[i]() } }
其中就有前面加入的flushSchedulerQueue,它主要用于执行queue中所有watcher的run方法,从而使组件们更新
for (index = 0; index < queue.length; index++) { watcher = queue[index] watcher.run() }
你平时什么时候会用到nextTick?
本文作者:毛超颖
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!