vue的狀態(tài)更新方式(異步更新解決)
狀態(tài)更新(異步更新解決)
在vue中狀態(tài)更新是異步的,這一點(diǎn)和react中的setstate類似。
解決方案
非組件解決方案:
<div id="example">{{message}}</div>var vm = new Vue({
? el: '#example',
? data: {
? ? message: '123'
? }
})
vm.message = 'new message' // 更改數(shù)據(jù)
vm.$el.textContent === 'new message' // false
Vue.nextTick(function () {
? vm.$el.textContent === 'new message' // true
})在組件內(nèi)使用 vm.$nextTick() 實(shí)例方法特別方便,因?yàn)樗恍枰?Vue ,并且回調(diào)函數(shù)中的 this 將自動綁定到當(dāng)前的 Vue 實(shí)例上:
Vue.component('example', {
? template: '<span>{{ message }}</span>',
? data: function () {
? ? return {
? ? ? message: '沒有更新'
? ? }
? },
? methods: {
? ? updateMessage: function () {
? ? ? this.message = '更新完成'
? ? ? console.log(this.$el.textContent) // => '沒有更新'
? ? ? this.$nextTick(function () {
? ? ? ? console.log(this.$el.textContent) // => '更新完成'
? ? ? })
? ? }
? }
})因?yàn)?$nextTick() 返回一個 Promise 對象,所以你可以使用新的 ES2016 async/await 語法完成相同的事情:methods: {
? updateMessage: async function () {
? ? this.message = 'updated'
? ? console.log(this.$el.textContent) // => '未更新'
? ? await this.$nextTick()
? ? console.log(this.$el.textContent) // => '已更新'
? }
}異步更新及nexttick
為什么需要異步更新
vue為了避免頻繁的操作DOM,采用異步的方式更新DOM。這些異步操作會通過nextTick函數(shù)將這些操作以cb的形式放到任務(wù)隊(duì)列中(以微任務(wù)優(yōu)先),當(dāng)每次tick結(jié)束之后就會去執(zhí)行這些cb,更新DOM。
異步更新內(nèi)部是最重要的就是nextTick方法,它負(fù)責(zé)將異步任務(wù)加入隊(duì)列和執(zhí)行異步任務(wù)。VUE 也將它暴露出來提供給用戶使用。在數(shù)據(jù)修改完成后,立即獲取相關(guān)DOM還沒那么快更新,使用nextTick便可以解決這一問題。
nextTick 原理
在下次DOM更新循環(huán)結(jié)束之后執(zhí)行的延遲回調(diào)。在修改數(shù)據(jù)之后立即使用該方法,獲取更新后的DOM。
/*存放異步執(zhí)行的回調(diào)*/
const callbacks = []
/*一個標(biāo)記位,如果已經(jīng)有timerFunc被推送到任務(wù)隊(duì)列中去則不需要重復(fù)推送*/
let pending = false
/*一個函數(shù)指針,指向函數(shù)將被推送到任務(wù)隊(duì)列中,等到主線程任務(wù)執(zhí)行完時,任務(wù)隊(duì)列中的timerFunc被調(diào)用*/
let timerFunc
/*
推送到隊(duì)列中下一個tick時執(zhí)行
cb 回調(diào)函數(shù)
ctx 上下文
*/
export function nextTick (cb?: Function, ctx?: Object) {
let _resolve
// 第一步 傳入的cb會被push進(jìn)callbacks中存放起來
callbacks.push(() => {
if (cb) {
try {
cb.call(ctx)
} catch (e) {
handleError(e, ctx, 'nextTick')
}
} else if (_resolve) {
_resolve(ctx)
}
})
// 檢查上一個異步任務(wù)隊(duì)列(即名為callbacks的任務(wù)數(shù)組)是否派發(fā)和執(zhí)行完畢了。pending此處相當(dāng)于一個鎖
if (!pending) {
// 若上一個異步任務(wù)隊(duì)列已經(jīng)執(zhí)行完畢,則將pending設(shè)定為true(把鎖鎖上)
pending = true
// 調(diào)用判斷Promise,MutationObserver,setTimeout的優(yōu)先級
timerFunc()
}
// 第三步執(zhí)行返回的狀態(tài)
if (!cb && typeof Promise !== 'undefined') {
return new Promise(resolve => {
_resolve = resolve
})
}
}
Vue 在更新 DOM 時是異步執(zhí)行的。只要偵聽到數(shù)據(jù)變化,Vue 將開啟一個隊(duì)列,并緩沖在同一事件循環(huán)中發(fā)生的所有數(shù)據(jù)變更。
如果同一個 watcher 被多次觸發(fā),只會被推入到隊(duì)列中一次。這種在緩沖時去除重復(fù)數(shù)據(jù)對于避免不必要的計(jì)算和 DOM 操作是非常重要的。
然后,在下一個的事件循環(huán)“tick”中,Vue 刷新隊(duì)列并執(zhí)行實(shí)際 (已去重的) 工作。
Vue 在內(nèi)部對異步隊(duì)列嘗試使用原生的 Promise.then、MutationObserver 和 setImmediate,如果執(zhí)行環(huán)境不支持,則會采用 setTimeout(fn, 0) 代替。
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
- vue在使用ECharts時的異步更新和數(shù)據(jù)加載詳解
- VUE異步更新DOM - 用$nextTick解決DOM視圖的問題
- 詳解Vue的異步更新實(shí)現(xiàn)原理
- 淺談Vuejs中nextTick()異步更新隊(duì)列源碼解析
- vue中的任務(wù)隊(duì)列和異步更新策略(任務(wù)隊(duì)列,微任務(wù),宏任務(wù))
- vue中$nextTick的用法講解
- Vue中this.$nextTick的作用及用法
- Vue中的nextTick作用和幾個簡單的使用場景
- Vue中this.$nextTick()的理解與使用方法
- 簡單理解Vue中的nextTick方法
- vue2.0$nextTick監(jiān)聽數(shù)據(jù)渲染完成之后的回調(diào)函數(shù)方法
- 深入理解Vue nextTick 機(jī)制
- Vue2異步更新及nextTick原理詳解
相關(guān)文章
vue項(xiàng)目開發(fā)環(huán)境工具node搭建過程
最近在開始接觸做vue框架的前端項(xiàng)目,以前用的前端比如html,js,css等都是比較原生的,寫好后直接瀏覽器打開就行,今天就先記錄一下vue的開發(fā)運(yùn)行搭建過程,感興趣的朋友一起看看吧2023-09-09
Vue props 單向數(shù)據(jù)流的實(shí)現(xiàn)
這篇文章主要介紹了Vue props 單向數(shù)據(jù)流的實(shí)現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-11-11
vue.js根據(jù)代碼運(yùn)行環(huán)境選擇baseurl的方法
本篇文章主要介紹了vue.js根據(jù)代碼運(yùn)行環(huán)境選擇baseurl的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-02-02
Vue實(shí)現(xiàn)當(dāng)前頁面刷新的4種方法舉例
我們在開發(fā)vue的頁面的時候,有時候會遇到需要刷新當(dāng)前頁面功能,但是vue框架自帶的router是不支持刷新當(dāng)前頁面功能,下面這篇文章主要給大家介紹了關(guān)于Vue實(shí)現(xiàn)當(dāng)前頁面刷新的4種方法,需要的朋友可以參考下2023-04-04
Vue?中?Promise?的then方法異步使用及async/await?異步使用總結(jié)
then?方法是?Promise?中?處理的是異步調(diào)用,異步調(diào)用是非阻塞式的,在調(diào)用的時候并不知道它什么時候結(jié)束,也就不會等到他返回一個有效數(shù)據(jù)之后再進(jìn)行下一步處理,這篇文章主要介紹了Vue?中?Promise?的then方法異步使用及async/await?異步使用總結(jié),需要的朋友可以參考下2023-01-01

