您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關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進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。