通常我們?cè)趹?yīng)用中會(huì)請(qǐng)求一些列表數(shù)據(jù),比如說(shuō)用戶(hù)列表、商品列表、文章列表等等......
而且有時(shí)候,我們并不會(huì)去修改這些請(qǐng)求回來(lái)的列表數(shù)據(jù),而只是單純地去展示它們,或者是把它們保存在全局狀態(tài)管理器里面(又稱(chēng)之為 Vuex)。請(qǐng)求數(shù)據(jù)列表的示意代碼如下所示:
export default {
? data: () => ({
? ? users: {}
? }),
? async created() {
? ? const users = await axios.get("/api/users");
? ? this.users = users;
? }
};
Vue 在默認(rèn)情況下,會(huì)將數(shù)組this.users中的,所有對(duì)象的第一層屬性設(shè)置為響應(yīng)式數(shù)據(jù)。
這對(duì)于大型的對(duì)象數(shù)組來(lái)說(shuō),性能成本非常的高。沒(méi)錯(cuò),的確有時(shí)候列表數(shù)據(jù)是有分頁(yè)的,但總會(huì)有一些情況下,是沒(méi)有進(jìn)行分頁(yè),繼而在前端展示的。
一個(gè)實(shí)際的例子就是谷歌地圖的標(biāo)記點(diǎn) markers 列表數(shù)據(jù),這就是一個(gè)擁有很多對(duì)象的大型數(shù)組。
所以,在一些特定的情況下,如果我們能夠阻止 Vue 將這些列表數(shù)據(jù)設(shè)置為響應(yīng)式的,那么我們就可以為項(xiàng)目帶來(lái)一些性能上的提升。實(shí)際上我們就是可以做到的,通過(guò)用Object.freeze方法,將獲取到的列表數(shù)據(jù)在賦值給組件之前,進(jìn)行凍結(jié):
export default {
? data: () => ({
? ? users: {}
? }),
? async created() {
? ? const users = await axios.get("/api/users");
? ? this.users = Object.freeze(users);
? }
};
記住,同樣地可以應(yīng)用到 Vuex 實(shí)踐中:
const mutations = {
? setUsers(state, users) {
? ? state.users = Object.freeze(users);
? }
};
順便說(shuō)一下,如果你確實(shí)有需要去修改請(qǐng)求得到的列表數(shù)據(jù),那么你仍然可以通過(guò)創(chuàng)建一個(gè)新的數(shù)組來(lái)實(shí)現(xiàn)。舉個(gè)例子,給原列表數(shù)據(jù)添加一個(gè)同類(lèi)型元素,可以這么操作:
state.users = Object.freeze([...state.users, user]);
來(lái)源:https://juejin.cn/post/6844903766982934535
來(lái)深究一下為什么Object.freeze()方法可以做到阻止Vue添加雙向數(shù)據(jù)綁定機(jī)制
大家應(yīng)該都知道Vue是通過(guò)Object.defineProperty()來(lái)修改屬性描述符中的setter和getter的,在getter中收集依賴(lài),在setter的時(shí)候觸發(fā)依賴(lài)。
在ES5開(kāi)始,所有的屬性都有了屬性描述符。決定是否可以修改一個(gè)屬性的描述符有兩個(gè):
是Writable:決定是否可以修改屬性的值;
另一個(gè)是Configurable:決定是否可以使用Object.defineProperty()來(lái)修改屬性描述符,并且也會(huì)禁止刪除這個(gè)屬性;
當(dāng)這兩個(gè)描述符同時(shí)為false時(shí),意味著這個(gè)屬性完全是一個(gè)常量,Vue不能通過(guò)Object.defineProperty()來(lái)添加雙向數(shù)據(jù)綁定。收集不了依賴(lài),也就做不了雙向數(shù)據(jù)綁定,就少添加很多watcher實(shí)例。
執(zhí)行Object.freeze()會(huì)執(zhí)行Object.seal()并吧所有的屬性的writable設(shè)置成false。
Object.seal()則會(huì)調(diào)用Object.preventExtensions()并把configurable設(shè)為false。
Object.preventExtensions()則會(huì)禁止對(duì)象添加新的屬性。
最后還有一個(gè)疑問(wèn),state.users = Object.freeze([...state.users, user]);會(huì)不會(huì)觸發(fā)視圖更新。
答案是會(huì)。users變量是定義在data中的,在Vue初始化initState的時(shí)候,會(huì)遍歷data中的所有屬性,添加監(jiān)聽(tīng)。也就是說(shuō)我們凍結(jié)的是users里面所有的屬性,并沒(méi)有凍結(jié)Vue中data,所以替換users會(huì)觸發(fā)雙向數(shù)據(jù)綁定
來(lái)源:http://www.itdecent.cn/p/56168a779849