Vue使用nextTick的原因和作用

在下次 DOM 更新循環(huán)結(jié)束之后執(zhí)行延遲回調(diào)。在修改數(shù)據(jù)之后立即使用這個(gè)方法,獲取更新后的 DOM。
疑問:
DOM 更新循環(huán)是指什么?
下次更新循環(huán)是什么時(shí)候?
修改數(shù)據(jù)之后使用,是加快了數(shù)據(jù)更新進(jìn)度嗎?
在什么情況下要用到?
原理
Vue 實(shí)現(xiàn)響應(yīng)式并不是數(shù)據(jù)發(fā)生變化之后 DOM 立即變化,而是按一定的策略進(jìn)行 DOM 的更新。
在 Vue 的文檔中,說明 Vue 是異步執(zhí)行 DOM 更新的。
具體來說,異步執(zhí)行的運(yùn)行機(jī)制如下。
(1)所有同步任務(wù)都在主線程上執(zhí)行,形成一個(gè)執(zhí)行棧(execution context stack)。
(2)主線程之外,還存在一個(gè)"任務(wù)隊(duì)列"(task queue)。只要異步任務(wù)有了運(yùn)行結(jié)果,就在"任務(wù)隊(duì)列"之中放置一個(gè)事件。
(3)一旦"執(zhí)行棧"中的所有同步任務(wù)執(zhí)行完畢,系統(tǒng)就會讀取"任務(wù)隊(duì)列",看看里面有哪些事件。那些對應(yīng)的異步任務(wù),于是結(jié)束等待狀態(tài),進(jìn)入執(zhí)行棧,開始執(zhí)行。
(4)主線程不斷重復(fù)上面的第三步。
簡單來說,Vue 在修改數(shù)據(jù)后,視圖不會立刻更新,而是等同一事件循環(huán)中的所有數(shù)據(jù)變化完成之后,再統(tǒng)一進(jìn)行視圖更新。
//改變數(shù)據(jù)vm.message = 'changed'//想要立即使用更新后的DOM。這樣不行,因?yàn)樵O(shè)置message后DOM還沒有更新console.log(vm.$el.textContent) // 并不會得到'changed'//這樣可以,nextTick里面的代碼會在DOM更新后執(zhí)行Vue.nextTick(function(){console.log(vm.$el.textContent) //可以得到'changed'})

第一個(gè) tick(圖例中第一個(gè)步驟,即'本次更新循環(huán)'):
1.首先修改數(shù)據(jù),這是同步任務(wù)。同一事件循環(huán)的所有的同步任務(wù)都在主線程上執(zhí)行,形成一個(gè)執(zhí)行棧,此時(shí)還未涉及 DOM 。2.Vue 開啟一個(gè)異步隊(duì)列,并緩沖在此事件循環(huán)中發(fā)生的所有數(shù)據(jù)改變。如果同一個(gè) watcher 被多次觸發(fā),只會被推入到隊(duì)列中一次。
第二個(gè) tick(圖例中第二個(gè)步驟,即'下次更新循環(huán)'):
同步任務(wù)執(zhí)行完畢,開始執(zhí)行異步 watcher 隊(duì)列的任務(wù),更新 DOM 。Vue 在內(nèi)部嘗試對異步隊(duì)列使用原生的 Promise.then 和 MessageChannel 方法,如果執(zhí)行環(huán)境不支持,會采用 setTimeout(fn, 0) 代替。
第三個(gè) tick(圖例中第三個(gè)步驟):
此時(shí)就是文檔所說的:下次 DOM 更新循環(huán)結(jié)束之后。
此時(shí)通過 Vue.nextTick 獲取到改變后的 DOM 。通過 setTimeout(fn, 0) 也可以同樣獲取到。
