摘要:因為平時使用都是傳回調的,所以很好奇什么情況下會為,去翻看官方文檔發現起新增如果沒有提供回調且在支持的環境中,則返回一個。這就對了,函數體內最后的判斷很明顯就是這個意思沒有回調支持。
Firstly, this paper is based on Vue 2.6.8一、源碼
剛開始接觸Vue的時候,哇nextTick好強,咋就在這里面寫就是dom更新之后,當時連什么macrotask、microtask都不知道(如果你也不是很清楚,推薦點這里去看一下,也有助于你更好地理解本文),再后來,寫的多了看得多了愈發膨脹了,就想看看這個nextTick到底是咋實現的
???????關于vue中nextTick方法的實現位于vue源碼下的src/core/util/next-tick.js,(下文所提到的next-tick.js都是指這個文件)由于篇幅原因就不全粘過來了,下面隨著分析會貼出主要代碼片段。
二、分析函數定義
將nextTick定義到Vue原型鏈上代碼位于src/core/instance/render.js,代碼如下
Vue.prototype.$nextTick = function (fn: Function) { return nextTick(fn, this) }
上述代碼中return的nextTick就是我們本文主角,他的定義如下
export function nextTick (cb?: Function, ctx?: Object) { // next-tick.js line87 let _resolve callbacks.push(() => { if (cb) { try { cb.call(ctx) } catch (e) { handleError(e, ctx, "nextTick") } } else if (_resolve) { _resolve(ctx) } }) if (!pending) { pending = true timerFunc() } if (!cb && typeof Promise !== "undefined") { return new Promise(resolve => { _resolve = resolve }) } }
1)函數參數cb?: Function,意味參數cb(callback)的類型為函數或undefined,ctx(context)同理,這種類型判斷是TypeScript的寫法。
??????同時可以看到我們常用的this.$nextTick()已經 在定義到原型鏈上時 給nextTick函數傳了ctx參數也就是指向當前組件的this。(這句話好繞,暴露了自己的語文水平)
2)函數體內callbacks是在next-tick.js line10定義的一個數組,判斷如果參數cb不為undefined,就把cb push到callbacks中,如果cb為undefined,則把_resolve(ctx)push到callbacks中。
??????因為平時使用都是傳回調的,所以很好奇cb什么情況下會為undefined,去翻看Vue官方文檔發現:
2.1.0 起新增:如果沒有提供回調且在支持 Promise 的環境中,則返回一個 Promise。
??????這就對了,函數體內最后的if判斷很明顯就是這個意思if (!cb && typeof Promise !== "undefined")沒有回調&&支持Promise。
??????在測試工程里寫如下代碼
created() { Vue.nextTick(undefined, { a: "in nextTick" }).then(ctx => { console.log(ctx.a) }) console.log("out nextTick") }
??????運行結果如下??????沒有任何問題(注意測試要使用Vue.nextTick而不是$nextTick,因為上文講到過$nextTick函數的ctx參數是當前組件)
3) 函數體內只剩下中間if (!pending),這段代碼很好懂,pending明顯是一個狀態位,而timerFunc()就應該是nextTick實現異步的核心了
timerFunc
??????在代碼中搜索timerFunc發現除了聲明和nextTick函數中,還有四處使用timerFunc的代碼片段,這四處代碼片段被嵌套在一個大的if else判斷里
if (typeof Promise !== "undefined" && isNative(Promise)) { // next-tick.js line42 timerFunc = ... } else if (!isIE && typeof MutationObserver !== "undefined" && ( isNative(MutationObserver) || MutationObserver.toString() === "[object MutationObserverConstructor]" )) { timerFunc = ... } else if (typeof setImmediate !== "undefined" && isNative(setImmediate)) { timerFunc = ... } else { timerFunc = ... }
??????可以看到nextTick優先使用microTask(Promise和MutationObserver)然后使用macroTask(setImmediate和setTimeout)這也符合尤大在2.6.0的更新日志中說的
next-tick: revert nextTick to alaways use microtask
??????首先這個alaways是不是拼錯了
??????不太對啊,我是不是對always有什么誤解,這不是明明還用macroTask的可能嗎
??????至于具體在不同的異步方式中是如何定義timerFunc的大同小異,如果仔細講解的話還要花費部分篇幅說明MutationObserver,畢竟我們的主角是nextTick,這里就不喧賓奪主,反正都是把timerFunc定義為在異步中調用flushCallbacks的函數,而函數flushCallbacks的定義在源碼中如下
function flushCallbacks () { // next-tick.js line13 pending = false const copies = callbacks.slice(0) callbacks.length = 0 for (let i = 0; i < copies.length; i++) { copies[i]() } }
?????? 因為callbacks里都是函數,所以一層深拷貝的方式就可以滿足復制需求,定義一個copies數組等于callbacks,然后清空callbacks,然后遍歷copies數組調用其中的函數。
三、總結??????nextTick實現流程大致是這樣的:
st=>operation: 將回調函數push到callbacks數組中 op=>operation: 調用timerFunc()根據不同情況采用不同異步方式調用flushCallbacks e=>operation: 刷新callbacks數組,遍歷并調用其中所有函數 st->op->e
??????能看懂一部分Vue源碼對于我這種入行不到一年的萌新還是非常有成就感的一件事,但是還有兩個地方有些疑慮,上文也都有提及:
1) 箭頭函數不能改變this指向為什么使用nextTick的時候可以使用箭頭函數,即nextTick函數定義中的cb.call(ctx)
2) 為什么更新日志中寫的是always use microtask,而我找到的源碼中是存在使用macroTask的情況的
??????后續將對問題的解決進行補充,也歡迎大佬在線評論傳道授業
2019/4/14
??????對于之前的兩個問題,我只能做出Vue本身使用了一部分babel的猜測,不過這兩個問題不影響整體邏輯的理解就是了
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/109274.html
摘要:盡量把所有異步代碼放在一個宏微任務中,減少消耗加快異步代碼的執行。我們知道,如果一個異步代碼就注冊一個宏微任務的話,那么執行完全部異步代碼肯定慢很多避免頻繁地更新。中就算我們一次性修改多次數據,頁面還是只會更新一次。 寫文章不容易,點個贊唄兄弟專注 Vue 源碼分享,文章分為白話版和 源碼版,白話版助于理解工作原理,源碼版助于了解內部詳情,讓我們一起學習吧研究基于 Vue版本 【2.5...
摘要:后來尤雨溪了解到是將回調放入的隊列。而且瀏覽器內部為了更快的響應用戶,內部可能是有多個的而的的優先級可能更高,因此對于尤雨溪采用的,甚至可能已經多次執行了的,都沒有執行的,也就導致了我們更新操 原發于我的博客。 前一篇文章已經詳細記述了Vue的核心執行過程。相當于已經搞定了主線劇情。后續的文章都會對其中沒有介紹的細節進行展開。 現在我們就來講講其他支線任務:nextTick和micro...
摘要:而中的回調函數則會在頁面渲染后才執行。還使用方法復制數組并把數組清空,這里的數組就是存放主線程執行過程中的函數所傳的回調函數集合主線程可能會多次使用方法。到這里就已經實現了根據環境選擇異步方法,并在異步方法中依次調用傳入方法的回調函數。 Vue.nextTick的應用場景 Vue 是采用異步的方式執行 DOM 更新。只要觀察到數據變化,Vue 將開啟一個隊列,并緩沖同一事件循環中發生的...
摘要:這是因為在運行時出錯,我們不這個錯誤的話,會導致整個程序崩潰掉。如果沒有向中傳入,并且瀏覽器支持的話,我們的返回的將是一個。如果不支持,就降低到用,整體邏輯就是這樣。。 我們知道vue中有一個api。Vue.nextTick( [callback, context] )他的作用是在下次 DOM 更新循環結束之后執行延遲回調。在修改數據之后立即使用這個方法,獲取更新后的 DOM。那么這個...
閱讀 3780·2023-04-25 21:09
閱讀 3129·2021-10-20 13:48
閱讀 2955·2021-09-24 10:25
閱讀 2937·2021-08-21 14:08
閱讀 1795·2019-08-30 15:56
閱讀 982·2019-08-30 15:52
閱讀 1848·2019-08-29 14:11
閱讀 3568·2019-08-29 11:01