成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Vue.js設計與實現之六-computed計算屬性的實現

開發 前端
計算屬性computed其實是一個懶執行的副作用函數,可以通過lazy選項使得副作用函數可以懶執行,被標記為懶執行的副作用函數可以通過手動執行。

1、寫在前面

在前面文章介紹了effect的實現,可以用于注冊副作用函數,同時允許一些選項參數options,可以指定調度器去控制副作用函數的執行時機和次數等。還有用于追蹤和收集依賴的track函數,以及用于觸發副作用函數重新執行的trigger函數,結合這些我們可以實現一個計算屬性--computed。

2、懶執行的effect

在研究計算屬性的實現之前,需要先去了解下懶執行的effect(lazy的effect)。在當前設計的effect函數中,它會在調用時立即執行傳遞過來的副作用函數。但是事實上,希望在某些場景并不希望它立即執行,而是在需要的時候才執行,前面了解到想要改變effect的執行可以在options參數中設置。

const data = {
name:"pingping",
age:18,
flag:true
}
const state = new Proxy(data,{
/*...*/
})
effect(()=>{
console.log(state.name);
},{
//指定lazy選項,這樣函數不會立即執行
lazy: true
})

就這樣,通過設置options選項,去修改effect函數的實現邏輯,當options.lazy為true時不會立即執行副作用函數:

// effect用于注冊副作用函數
function effect(fn,options={}){
const effectFn = ()=>{
// 調用函數完成清理遺留副作用函數
cleanupEffect(effectFn)
// 當調用effect注冊副作用函數時,將副作用函數fn賦值給activeEffect
activeEffect = effectFn;
// 在副作用函數執行前壓棧
effectStack.push(effectFn)
// 執行副作用函數
fn();
// 執行完畢后出棧
effectStack.pop()
activeEffect = effectStack[effectStack.length - 1]
}
// 將options掛載到effectFn函數上
effectFn.options = options
//deps是用于存儲所有與該副作用函數相關聯的依賴集合
effectFn.deps = [];
// 只有非lazy的時候才執行
if(!options.lazy){
// 執行副作用函數effectFn
effectFn()
}
//否則返回副作用函數
return effectFn
}

在上面代碼片段中,在effect函數中先判斷了是否需要懶執行,對此會判斷options.lazy的值為true時,則將effectFn副作用函數作為參數返回到effect。這樣,用戶在調用執行effect函數時,可以通過返回值去拿到對應的effectFn函數,這樣可以手動執行該函數。

const effectFn = effect(()=>{
console.log(state.name);
},{
//指定lazy選項,這樣函數不會立即執行
lazy: true
});
//手動執行副作用函數
effectFn();

但是僅僅實現手動執行副作用函數,對于我們的使用意義并不大,如果將返回到effect的副作用函數作為getter,那么通過這個取值函數就能獲取返回任何值。

const effectFn = effect(
()=>state.name + state.age,
{
//指定lazy選項,這樣函數不會立即執行
lazy: true
});

//手動執行副作用函數,可以獲取到返回的值
const value = effectFn();

這樣就可以實現在調用的時候,手動執行獲取到各種想要得到的值。在effect函數內部只需要做出些改變,只需要在執行副作用函數時將副作用的值返回即可:

// effect用于注冊副作用函數
function effect(fn,options={}){
const effectFn = ()=>{
// 調用函數完成清理遺留副作用函數
cleanupEffect(effectFn)
// 當調用effect注冊副作用函數時,將副作用函數fn賦值給activeEffect
activeEffect = effectFn;
// 在副作用函數執行前壓棧
effectStack.push(effectFn)
// 執行副作用函數,將執行結果存儲到res
const res = fn();
// 執行完畢后出棧
effectStack.pop()
activeEffect = effectStack[effectStack.length - 1]
// 將res作為effectFn的返回值
return res
}
// 將options掛載到effectFn函數上
effectFn.options = options
//deps是用于存儲所有與該副作用函數相關聯的依賴集合
effectFn.deps = [];
// 只有非lazy的時候才執行
if(!options.lazy){
// 執行副作用函數effectFn
effectFn()
}
//否則返回副作用函數
return effectFn

}

現在,我們已經實現了能夠進行懶執行的副作用函數,能夠拿到執行返回的結果,做后續的處理。

3、computed屬性

懶計算的computed屬性

其實,基于前面的設計和代碼實現,大概有了computed屬性函數的實現雛形,就是接收一個getter函數作為副作用函數,用于創建一個懶執行的effect。computed函數的執行會返回包含一個訪問器屬性的對象,只有在讀取value值的時候才會去執行effectFn并返回結果。

function computed(getter){
const effectFn = effect(
getter,
{
//指定lazy選項,這樣函數不會立即執行
lazy: true
});
const state = {
//當對value進行讀取操作時,執行effectFn并將結果進行返回
get value(){
return effectFn();
}
}
return state;
}

在上面代碼中,只是粗略做了懶計算處理,只有在真正對sumRes.value的值進行讀取操作時,才會去進行計算并得到值。但是在進行多次讀取sumRes.value的值,每次訪問計算得到的值都是相同的,并不符合我們需要使用上次計算值的要求。『計算屬性需要有緩存機制,這樣就可以使用到上次計算的結果。』

const sumRes = computed(()=>state.name + state.age);
console.log("hello", sumRes.value);
console.log("hello", sumRes.value);
console.log("hello", sumRes.value);

運行結果:

之所以發生這種情況,多次讀取sumRes.value的值時,每次訪問都會重新調用effectFn重新計算。

帶有緩存的computed

為了解決前面獲取不到上次計算值的問題,需要在實現computed函數時,添加對計算值的緩存操作。其實實現很簡單,就是添加兩個變量value和dirty,value用于緩存上次計算的值,dirty則標識是否需要重新計算。

function computed(getter){
let value;
let dirty = true;
const effectFn = effect(
getter,
{
//指定lazy選項,這樣函數不會立即執行
lazy: true
//在調度器重置dirtytrue
scheduler(){
dirty = true
}
});
const state = {
//當對value進行讀取操作時,執行effectFn并將結果進行返回
get value(){
//只有當dirty標識為true值時,才會將計算值進行緩存,下一次訪問直接使用緩存的值
if(dirty){
value = effectFn();
dirty = false
}
return value
}
}
return state;
}

在上面代碼中,初始化設置dirty為true,這樣就會把計算值進行緩存,下次進行同樣computed計算操作時,就會直接使用緩存的值,而非每次重新計算。同時,在computed函數的effect中添加scheduler屬性,在函數內部將dirty的值重置為true,在下次訪問sumRes.value時重新調用effectFn的計算值。

const sumRes = computed(()=>state.name + state.age);
console.log("hello", sumRes.value);
console.log("hello", sumRes.value);
console.log("hello", sumRes.value);
state.age++;
console.log("hello", sumRes.value);

執行結果為:

但是,在當前設計的計算屬性在另一個effect函數中讀取時,修改響應數據state上的屬性值并不會觸發副作用函數的重新渲染。其實根本原因就是這里存在一個effect嵌套問題,computed內部是effect函數實現的,而在effect中讀取computed的值相當于對effect進行了嵌套,外層的effect不會被內層effect的響應式數據收集。

當然,問題很簡單,解決方法同樣很簡單。只需要在讀取計算屬性值的時候,手動調用track函數進行追蹤,當計算屬性依賴的響應式數據發生變化時,手動調用trigger函數觸發響應:

function computed(getter){
let value;
let dirty = true;

const effectFn = effect(
getter,
{
//指定lazy選項,這樣函數不會立即執行
lazy: true,
//在調度器重置dirtytrue
scheduler(){
dirty = true
trigger(state, "value")
}
}
);
const state = {
//當對value進行讀取操作時,執行effectFn并將結果進行返回
get value(){
//只有當dirty標識為true值時,才會將計算值進行緩存,下一次訪問直接使用緩存的值
if(dirty){
value = effectFn();
dirty = false
}
// 對value進行取值操作時,手動調用track函數進行追蹤
track(state, "value")
return value
}
}
return state;
}

寫一段簡單的demo進行實驗:

const sumRes = computed(()=>state.name + state.age);
console.log("hello", sumRes.value);
console.log("hello", sumRes.value);
console.log("hello", sumRes.value);
effect(()=>{
console.log(sumRes.value);
})
state.age++

console.log("hello", sumRes.value);

執行結果:

根據上面的實現demo可以分析出對應的計算屬性的響應聯系圖:

計算屬性的響應聯系

4、寫在最后

計算屬性computed其實是一個懶執行的副作用函數,可以通過lazy選項使得副作用函數可以懶執行,被標記為懶執行的副作用函數可以通過手動執行。在讀取計算屬性的值時,可以手動執行副作用函數,在依賴的響應式數據發生變化時,通過scheduler將dirty標記設置為true,即為臟數據,在下次讀取計算屬性的值,就會重新計算得到真正的值。

責任編輯:姜華 來源: 前端一碼平川
相關推薦

2022-04-12 08:08:57

watch函數options封裝

2022-04-25 07:36:21

組件數據函數

2022-04-01 08:08:27

Vue.js框架命令式

2022-04-04 16:53:56

Vue.js設計框架

2022-04-18 08:09:44

渲染器DOM掛載Vue.js

2022-05-03 21:18:38

Vue.js組件KeepAlive

2022-04-14 09:35:03

Vue.js設計Reflect

2022-04-05 16:44:59

系統Vue.js響應式

2022-04-17 09:18:11

響應式數據Vue.js

2022-04-09 17:53:56

Vue.js分支切換嵌套的effect

2022-04-03 15:44:55

Vue.js框架設計設計與實現

2022-04-16 13:59:34

Vue.jsJavascript

2022-04-26 05:55:06

Vue.js異步組件

2022-04-20 09:07:04

Vue.js的事件處理

2022-04-19 23:01:54

Vue.jsDOM節點DOM樹

2016-11-01 19:10:33

vue.js前端前端框架

2023-12-11 07:34:37

Computed計算屬性Vue3

2024-05-17 09:51:11

2019-04-01 19:38:28

Vue.jsJavascript前端

2021-09-18 10:07:23

開發技能代碼
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩精品国产精品 | 亚洲情综合五月天 | 国产精品美女久久久久aⅴ国产馆 | 欧美日韩在线免费观看 | 日韩av一二三区 | 欧美激情啪啪 | 成人欧美一区二区三区黑人孕妇 | 91极品视频 | 中文字幕av色 | www.788.com色淫免费 | 色妹子综合网 | 日韩一区二区免费视频 | av中文字幕在线 | 久久黄网 | 在线不卡视频 | 日本精品视频 | 久操av在线 | 日韩成人免费av | 在线观看成人av | 国产精久久久久久久妇剪断 | 国产精品久久久久久久久久久久久 | 久久国产精品99久久久久 | 欧美一区二区三区在线免费观看 | 欧美午夜精品 | 一区二区三区在线免费观看 | 国产成人网 | 天天av天天好逼 | 少妇久久久 | 欧美一区二区三区在线 | 亚洲精视频| 一级毛片大全免费播放 | 色综合天天综合网国产成人网 | a级黄色片在线观看 | 丁香五月网久久综合 | 久久av一区二区三区 | 99热电影| 91精品国产91久久久久游泳池 | 久久精品99久久 | 久久成人一区 | 成人一区二区三区在线观看 | 一区二区三区中文字幕 |