这期内容当中小编将会给大家带来有关NextTick的作用有哪些,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。
在vue中每次监听到数据变化的时候,都会去调用notify通知依赖更新,触发watcher中的update方法。
update () { /* istanbul ignore else */ if (this.lazy) { } else if (this.sync) { } else { this.get() //queueWatcher(this) } }
如果通过watcher中的get方法去重新渲染组件,那么在渲染的过程中假如多次更新数据会导致同一个watcher被触发多次,这样会导致重复的数据计算和DOM的操作。如下图所示,修改3次message之后DOM被操作了3次。
为了解决上述问题,不去直接调用get方法而是将每次调用update方法后需要批处理的wather暂存到一个队列当中,如果同一个 watcher 被多次触发,通过wacther 的id属性对其去重,只会被推入到队列中一次。然后,等待所有的同步代码执行完毕之后在下一个的事件循环中,Vue 刷新队列并执行实际 (已去重的) 工作。
let has: { [key: number]: ?true } = {} let waiting = false export function queueWatcher (watcher: Watcher) { const id = watcher.id //对watcher去重 if (has[id] == null) { has[id] = true queue.push(watcher); if (!waiting) { //节流 waiting = true nextTick(flushSchedulerQueue) } }
调用watcher的run方法异步更新DOM
let has: { [key: number]: ?true } = {} function flushSchedulerQueue () { let watcher, id queue.sort((a, b) => a.id - b.id) for (index = 0; index < queue.length; index++) { watcher = queue[index] if (watcher.before) { watcher.before() } id = watcher.id has[id] = null //清空id watcher.run() //更新值 } resetSchedulerState() //清空watcher队列 } function resetSchedulerState () { index = queue.length = 0 has = {} waiting = false }
在vue内部调用nextTick(flushSchedulerQueue),vm.$nextTick方法调用的也是nextTick()方法
Vue.prototype.$nextTick = function (cb) { nextTick(cb,this); };
那么多次调用nextTick方法是怎么处理的呢?
const callbacks = [] let pending = false export function nextTick (cb?: Function, ctx?: Object) { callbacks.push(() => { if (cb) { try { cb.call(ctx) } catch (e) { handleError(e, ctx, 'nextTick') } } }) if (!pending) { pending = true timerFunc() } }
nextTick将所有的回调函数暂存到了一个队列中,然后通过异步调用更新去依次执行队列中的回调函数。
function flushCallbacks () { pending = false const copies = callbacks.slice(0) callbacks.length = 0 for (let i = 0; i < copies.length; i++) { copies[i]() } }
nextTick函数中异步更新对兼容性做了处理,使用原生的 Promise.then、MutationObserver 和 setImmediate,如果执行环境不支持,则会采用 setTimeout(fn, 0) 代替。
Promise
if (typeof Promise !== 'undefined' && isNative(Promise)) { const p = Promise.resolve() timerFunc = () => { p.then(flushCallbacks) } }
MutationObserver
MutationObserver 它会在指定的DOM发生变化时被调用。创建了一个文本DOM,通过监听字符值的变化,当文本字符发生变化的时候调用回调函数。
if (!isIE && typeof MutationObserver !== 'undefined' && ( isNative(MutationObserver) || MutationObserver.toString() === '[object MutationObserverConstructor]' )) { 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) } }
setImmediate
setImmediate该方法用作把一些需要持续运行的操作放在一个其他函数里,在浏览器完成后面的其他语句后,就立即执行此替换函数。
if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) { timerFunc = () => { setImmediate(flushCallbacks) } }else{ timerFunc = () => { setTimeout(flushCallbacks, 0) } }
总结
vue渲染DOM的时候触发set方法中的去依赖更新,在更新的过程中watcher不是每次都去执行去触发DOM的更新,而是通过对wather的去重之后,通过nextTick异步调用触发DOM更新。
nextTick()就是一个异步函数,在异步函数中通过队列批处理nextTick传入的回调函数cb,但是队列彼此不是同时进行的,通过节流的方式依次执行。
上述就是小编为大家分享的NextTick的作用有哪些了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注亿速云行业资讯频道。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。