使用過Vue的小夥伴們都知道,Vue裏的nextTick能夠獲取到更新後的DOM, 今天我就來說解下nextTick裏面究竟作了什麼?javascript
開始講解前,咱們須要知道了解一個概念,那就是Event Loopjava
Event Loop翻譯過來就是事件循環, 一個Event Loop會包括一個或多個task隊列,持續線程會從隊列中取出最先進入隊列的任務進行執行,被取出的任務就叫作macroTask(宏任務), 每一個macroTask都有一個任務源, 每一個macroTask處理完以後就從隊列中取出下一個時間最先進入的macroTask再重執行ios
任務源:數組
```
1. script
2. 事件
3. Dom交互
4. I/O
5. UI Render
6. setTimeout
7. setInterval
8. requestAnimationFrame
.....
```
複製代碼
也就是說碰到以上幾種狀況就會產生一個macroTask而且推入到隊列中promise
miscroTask(微任務)瀏覽器
執行完每一個macroTask以後,主線程會去檢查該macroTask
下的microTask是否爲空,若是不爲空,則按照時間順序從早到晚取出,若是途中有遇到新的microTask, 那麼會繼續將該microTask推入到microTask隊列裏網絡
UI Render(重點)函數
伴隨着miscroTask隊列的清空,主線程就會執行UI Render, 也就是渲染界面,可是瀏覽器它並不會每次在UI Render任務下必定會渲染界面,視狀況而言,如今主流瀏覽器通常都是按照60HZ 也就是16.7ms刷新頻率進行渲染(不是精確估量),一個macroTask一般是小於16.7ms, 因此瀏覽器每次會根據狀況進行渲染oop
總結下一個循環性能
1. 從macroTask隊列裏取出最先添加進去的
2. 開始執行task, 途中若是遇到新的macroTask,就會將其添加到macroTask隊列的最後面
3. 執行完macroTask以後,event loop會去尋找microTask隊列
4. 一樣的道理,若是途中遇到新的microTask,將其放入該macroTask下的microTask隊列最後面
5. 執行完microTask,會執行UI Render macroTask
6. 瀏覽器會根據現有狀況決定是否更新DOM,一般是按照60HZ的頻率去更新
7. 至此,一個event loop結束了
複製代碼
咱們開始分析nextTick
1. this.$nextTick(cb)
2. this.$nextTick().then(cb)
複製代碼
上圖中咱們看到了主要是由timerFunc這個函數來進行調用回調, 那麼咱們下面來着重介紹這個函數,首先看下源碼
咱們能夠看到timerFunc在不一樣狀況下不一樣的賦值狀況
首先會判斷瀏覽器是否支持promise屬性, 若是支持, timerFunc就會被賦值成Promise, 這裏有個小小的問題,那就是在ios下,雖然是具有Pormise對象,而且會將它推入到microTask隊列裏,可是隊列卻不會更新,這個時候須要添加一個macroTask來強制刷新microTask隊列
MutationObserver, 相信不少人並不清楚這個Api, 這是一個可以監聽DOM變化的API,而且屬於microTask, 優先級低於Promise 在建立一個新的文本節點後,手動更改其文本節點來觸發microTask,
這裏會有個小小的問題:
該文本節點渲染成功後,必定能表明其餘的DOM渲染成功了嗎?
這是個備選方案, 主要仍是由於它是一個微任務,因此才使用它,並非由於它監聽了DOM
微任務都失敗後, 退而求其次,選擇setImmediate, 這是一個只有高版本IE和Edge瀏覽器纔可能擁有的API, 其主要是用於計算大量數據的時候使用
最後就是setTimeout
看到這裏,你會不會有疑惑?
上面的代碼並無說明nextTick是在監聽DOM更新後才執行的? What????當時腦殼就duang了一下
那麼接下來講的就是重中之重
DOM Tree的更新是實時的,DOM Tree的更新是實時的,DOM Tree的更新是實時的, 重要的事說3遍, 這意味着你無需去監聽DOM 更新, 你對DOM的操做是可以實時獲得反饋的,上一行代碼操做了DOM,下一行就能獲取到
那麼有人就會產生疑惑了, nextTick到底是幹嗎的?
nextTick的做用是將收集Watcher從隊列中一個個取出,而且更改數據,來一次性渲染DOM, 咱們知道操做DOM的代價是昂貴的, 瀏覽器打開一個網頁後會開啓一個進程,進程是由線程組成的, 那麼在打開的同時,
1. GUI渲染線程
2. js引擎線程(主線程)
3. EventLoop輪訓處理線程
4. 其餘線程,例如網絡
複製代碼
跨線程操做代價是昂貴的,因此作到一次性渲染Dom,能夠有效的優化性能!!
nextTick並非用來監聽DOM變動,由於DOM變動是可以實時獲取到的,它的做用是一次性更改數據,而且渲染DOM
3Q!