最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue3?響應(yīng)式系統(tǒng)實現(xiàn)?computed

 更新時間:2022年06月30日 10:49:45   作者:??zxg_神說要有光????  
這篇文章主要介紹了?Vue3?響應(yīng)式系統(tǒng)實現(xiàn)?computed,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,感興趣的小伙伴可以參考一下

前言

上篇文章我們實現(xiàn)了基本的響應(yīng)式系統(tǒng),這篇文章繼續(xù)實現(xiàn) computed。

首先,我們簡單回顧一下:

響應(yīng)式系統(tǒng)的核心就是一個 WeakMap --- Map --- Set 的數(shù)據(jù)結(jié)構(gòu)。

WeakMap 的 key 是原對象,value 是響應(yīng)式的 Map。這樣當對象銷毀的時候,對應(yīng)的 Map 也會銷毀。

Map 的 key 就是對象的每個屬性,value 是依賴這個對象屬性的 effect 函數(shù)的集合 Set。然后用 Proxy 代理對象的 get 方法,收集依賴該對象屬性的 effect 函數(shù)到對應(yīng) key 的 Set 中。還要代理對象的 set 方法,修改對象屬性的時候調(diào)用所有該 key 的 effect 函數(shù)。

上篇文章我們按照這樣的思路實現(xiàn)了一個比較完善的響應(yīng)式系統(tǒng),然后今天繼續(xù)實現(xiàn) computed。

實現(xiàn) computed

首先,我們把之前的代碼重構(gòu)一下,把依賴收集和觸發(fā)依賴函數(shù)的執(zhí)行抽離成 track 和 trigger 函數(shù):

邏輯還是添加 effect 到對應(yīng)的 Set,以及觸發(fā)對應(yīng) Set 里的 effect 函數(shù)執(zhí)行,但抽離出來清晰多了。

然后繼續(xù)實現(xiàn) computed。

computed 的使用大概是這樣的:

const value = computed(() => {
    return obj.a + obj.b;
});

對比下 effect:

effect(() => {
    console.log(obj.a);
});

區(qū)別只是多了個返回值。

所以我們基于 effect 實現(xiàn) computed 就是這樣的:

function computed(fn) {
    const value = effect(fn);
   return value
}

當然,現(xiàn)在的 effect 是沒有返回值的,要給它加一下:

只是在之前執(zhí)行 effect 函數(shù)的基礎(chǔ)上把返回值記錄下來返回,這個改造還是很容易的。

現(xiàn)在 computed 就能返回計算后的值了:

但是現(xiàn)在數(shù)據(jù)一遍,所有的 effect 都執(zhí)行了,而像 computed 這里的 effect 是沒必要每次都重新執(zhí)行的,只需要在數(shù)據(jù)變了之后執(zhí)行。

所以我們添加一個 lazy 的 option 來控制 effect 不立刻執(zhí)行,而是把函數(shù)返回讓用戶自己執(zhí)行。

然后 computed 里用 effect 的時候就添加一個 lazy 的 option,讓 effect 函數(shù)不執(zhí)行,而是返回出來。

computed 里創(chuàng)建一個對象,在 value 的 get 觸發(fā)時調(diào)用該函數(shù)拿到最新的值:

我們測試下:

可以看到現(xiàn)在 computed 返回值的 value 屬性是能拿到計算后的值的,并且修改了 obj.a. 之后會重新執(zhí)行計算函數(shù),再次拿 value 時能拿到新的值。

只是多執(zhí)行了一次計算,這是因為 obj.a 變的時候會執(zhí)行所有的 effect 函數(shù):

這樣每次數(shù)據(jù)變了都會重新執(zhí)行 computed 的函數(shù)來計算最新的值。

這是沒有必要的,effect 的函數(shù)是否執(zhí)行應(yīng)該也是可以控制的。所以我們要給它加上調(diào)度的功能:

可以支持傳入 schduler 回調(diào)函數(shù),然后執(zhí)行 effect 的時候,如果有 scheduler 就傳給它讓用戶自己來調(diào)度,否則才執(zhí)行 effect 函數(shù)。

這樣用戶就可以自己控制 effect 函數(shù)的執(zhí)行了:

然后再試一下剛才的代碼:

可以看到,obj.a 變了之后并沒有執(zhí)行 effect 函數(shù)來重新計算,因為我們加了 sheduler 來自己調(diào)度。這樣就避免了數(shù)據(jù)變了以后馬上執(zhí)行 computed 函數(shù),可以自己控制執(zhí)行。

現(xiàn)在還有一個問題,每次訪問 res.value 都要計算:

能不能加個緩存呢?只有數(shù)據(jù)變了才需要計算,否則直接拿之前計算的值。

當然是可以的,加個標記就行:

scheduler 被調(diào)用的時候就說明數(shù)據(jù)變了,這時候 dirty 設(shè)置為 true,然后取 value 的時候就重新計算,之后再改為 false,下次取 value 就直接拿計算好的值了。

我們測試下:

我們訪問 computed 值的 value 屬性時,第一次會重新計算,后面就直接拿計算好的值了。

修改它依賴的數(shù)據(jù)后,再次訪問 value 屬性會再次重新計算,然后后面再訪問就又會直接拿計算好的值了。

至此,我們完成了 computed 的功能。

但現(xiàn)在的 computed 實現(xiàn)還有一個問題,比如這樣一段代碼:

let res = computed(() => {
    return obj.a + obj.b;
});
effect(() => {
    console.log(res.value);
});

我們在一個 effect 函數(shù)里用到了 computed 值,按理說 obj.a 變了,那 computed 的值也會變,應(yīng)該觸發(fā)所有的 effect 函數(shù)。

但實際上并沒有:

這是為什么呢?

這是因為返回的 computed 值并不是一個響應(yīng)式的對象,需要把它變?yōu)轫憫?yīng)式的,也就是 get 的時候 track 收集依賴,set 的時候觸發(fā)依賴的執(zhí)行:

我們再試一下:

現(xiàn)在 computed 值變了就能觸發(fā)依賴它的 effect 了。至此,我們的 computed 就很完善了。

完整代碼如下:

const data = {
    a: 1,
    b: 2
}
let activeEffect
const effectStack = [];
function effect(fn, options = {}) {
  const effectFn = () => {
      cleanup(effectFn)
      activeEffect = effectFn
      effectStack.push(effectFn);
      const res = fn()
      effectStack.pop()
      activeEffect = effectStack[effectStack.length - 1]
      return res
  }
  effectFn.deps = []
  effectFn.options = options;
  if (!options.lazy) {
    effectFn()
  }
  return effectFn
}
function computed(fn) {
    let value
    let dirty = true
    const effectFn = effect(fn, {
        lazy: true,
        scheduler(fn) {
            if(!dirty) {
                dirty = true
                trigger(obj, 'value');
            }
        }
    });
    const obj = {
        get value() {
            if (dirty) {
                value = effectFn()
                dirty = false
            }
            track(obj, 'value');
            console.log(obj);
            return value
        }
    }
    return obj
}
function cleanup(effectFn) {
    for (let i = 0; i < effectFn.deps.length; i++) {
        const deps = effectFn.deps[i]
        deps.delete(effectFn)
    }
    effectFn.deps.length = 0
}
const reactiveMap = new WeakMap()
const obj = new Proxy(data, {
    get(targetObj, key) {
        track(targetObj, key);

        return targetObj[key]
   },
   set(targetObj, key, newVal) {
        targetObj[key] = newVal

        trigger(targetObj, key)
    }
})
function track(targetObj, key) {
    let depsMap = reactiveMap.get(targetObj)
    if (!depsMap) {
    reactiveMap.set(targetObj, (depsMap = new Map()))
    }
    let deps = depsMap.get(key)
    if (!deps) {
    depsMap.set(key, (deps = new Set()))
    }
    deps.add(activeEffect)
    activeEffect.deps.push(deps);
}
function trigger(targetObj, key) {
    const depsMap = reactiveMap.get(targetObj)
    if (!depsMap) return
    const effects = depsMap.get(key)
    const effectsToRun = new Set(effects)
    effectsToRun.forEach(effectFn => {
        if(effectFn.options.scheduler) {
            effectFn.options.scheduler(effectFn)
        } else {
            effectFn()
        }
    })
}

總結(jié)

上篇文章我們實現(xiàn)了響應(yīng)式的核心數(shù)據(jù)結(jié)構(gòu),依賴的收集、數(shù)據(jù)變化后通知依賴函數(shù)執(zhí)行。今天我們在那基礎(chǔ)上實現(xiàn)了 computed。我們改造了 effect 函數(shù),讓它返回傳入的 fn,然后在 computed 里自己執(zhí)行來拿到計算后的值。

我們又支持了 lazy 和 scheduler 的 option,lazy 是讓 effect 不立刻執(zhí)行傳入的函數(shù),scheduler 是在數(shù)據(jù)變動觸發(fā)依賴執(zhí)行的時候回調(diào) sheduler 來調(diào)度。

我們通過標記是否 dirty 來實現(xiàn)緩存,當 sheduler 執(zhí)行的時候,說明數(shù)據(jù)變了,把 dirty 置為 true,重新計算 computed 的值,否則直接拿緩存。此外,computed 的 value 并不是響應(yīng)式對象,我們需要單獨的調(diào)用下 track 和 trigger。這樣,我們就實現(xiàn)了完善的 computed 功能,vue3 內(nèi)部也是這樣實現(xiàn)的。

到此這篇關(guān)于 Vue3 響應(yīng)式系統(tǒng)實現(xiàn) computed的文章就介紹到這了,更多相關(guān) Vue3 computed內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue 解決循環(huán)引用組件報錯的問題

    vue 解決循環(huán)引用組件報錯的問題

    今天小編就為大家分享一篇vue 解決循環(huán)引用組件報錯的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-09-09
  • 使用Vant完成Dialog彈框案例

    使用Vant完成Dialog彈框案例

    這篇文章主要介紹了使用Vant完成Dialog彈框案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • vue2 element 彈出框拖拽會出現(xiàn)一層陰影問題解決方法

    vue2 element 彈出框拖拽會出現(xiàn)一層陰影問題解決方法

    這篇文章主要介紹了vue2 element 彈出框拖拽會出現(xiàn)一層陰影問題解決方法,因增加 draggable 屬性導(dǎo)致我彈窗表單清空文本框時,從右向左選中字體會出現(xiàn)拖拽陰影效果,本文給大家介紹vue2 element 彈出框拖拽會出現(xiàn)一層陰影問題解決方法,感興趣的朋友一起看看吧
    2024-01-01
  • 封裝 axios+promise通用請求函數(shù)操作

    封裝 axios+promise通用請求函數(shù)操作

    這篇文章主要介紹了封裝 axios+promise通用請求函數(shù)操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • 詳細聊聊前端如何實現(xiàn)token無感刷新(refresh_token)

    詳細聊聊前端如何實現(xiàn)token無感刷新(refresh_token)

    實現(xiàn)token無感刷新對于前端來說是一項非常常用的技術(shù),其本質(zhì)是為了優(yōu)化用戶體驗,下面這篇文章主要給大家介紹了關(guān)于前端如何實現(xiàn)token無感刷新(refresh_token)的相關(guān)資料,需要的朋友可以參考下
    2022-11-11
  • Vue2和Vue3在v-for遍歷時ref獲取dom節(jié)點的區(qū)別及說明

    Vue2和Vue3在v-for遍歷時ref獲取dom節(jié)點的區(qū)別及說明

    這篇文章主要介紹了Vue2和Vue3在v-for遍歷時ref獲取dom節(jié)點的區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Vue.js學習之計算屬性

    Vue.js學習之計算屬性

    Vue.js 的內(nèi)聯(lián)表達式非常方便,但它最合適的使用場景是簡單的布爾操作或字符串拼接。如果涉及更復(fù)雜的邏輯,你應(yīng)該使用計算屬性。下面這篇文章主要給大家介紹了Vue.js中的計算屬性,需要的朋友可以參考借鑒,一起來看看吧。
    2017-01-01
  • vue基于better-scroll仿京東分類列表

    vue基于better-scroll仿京東分類列表

    這篇文章主要為大家詳細介紹了vue基于better-scroll仿京東分類列表,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-06-06
  • vue3?錨點定位的多種實現(xiàn)方式

    vue3?錨點定位的多種實現(xiàn)方式

    這篇文章主要介紹了vue3?多種方法的錨點定位,使用?Vue?Router?導(dǎo)航守衛(wèi)可以簡化導(dǎo)航邏輯、統(tǒng)一管理導(dǎo)航邏輯和進行權(quán)限控制,但需要學習和理解相關(guān)概念,并且需要手動編寫和管理導(dǎo)航守衛(wèi)的邏輯,本文給大家介紹的非常詳細,需要的朋友可以參考下
    2023-07-07
  • uniApp前端實現(xiàn)文字識別并提取詳細分析

    uniApp前端實現(xiàn)文字識別并提取詳細分析

    這篇文章主要介紹了如何實現(xiàn)文字圖片分析的功能,包括頁面結(jié)構(gòu)、樣式和腳本邏輯,主要步驟包括獲取access_token、將圖片轉(zhuǎn)換為Base64格式、上傳至百度文字識別接口并處理返回結(jié)果,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2025-02-02

最新評論

根河市| 荣成市| 阿坝县| 南康市| 正宁县| 弥渡县| 嘉定区| 鹿泉市| 汕头市| 农安县| 新竹县| 明光市| 米泉市| 常州市| 明水县| 蓬溪县| 龙口市| 台中市| 彭州市| 新乐市| 东乌| 兖州市| 印江| 阿巴嘎旗| 定远县| 土默特右旗| 昌黎县| 海安县| 察哈| 镇坪县| 阿合奇县| 桦甸市| 龙陵县| 东乡族自治县| 秦皇岛市| 澄城县| 梁平县| 中方县| 铜鼓县| 磐石市| 天柱县|