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

淺談vue3中effect與computed的親密關(guān)系

 更新時(shí)間:2019年10月10日 09:25:01   作者:Victor細(xì)節(jié)  
這篇文章主要介紹了淺談vue3中effect與computed的親密關(guān)系,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

在我剛看完vue3響應(yīng)式的時(shí)候,心中就有一個(gè)不可磨滅的謎團(tuán),讓我茶不思飯不想,總想生病。那么這個(gè)謎團(tuán)是什么呢?就是在響應(yīng)式中一直穿行在tranger跟track之間的effect。如果單純的響應(yīng)式原理根本就用不上effect,那么effect到底是干什么的呢?

船到橋頭自然直,柳岸花明又一村??嘈娜颂觳回?fù),偶然間我看到了effect測(cè)試代碼用例!

it('should observe basic properties', () => {
 let dummy
 const counter = reactive({ num: 0 })
 effect(() => (dummy = counter.num))

 expect(dummy).toBe(0)
 counter.num = 7
 expect(dummy).toBe(7)
})

解釋一下,這段代碼

  • 首先聲明dummy變量,然后在effect的回調(diào)中把已響應(yīng)的對(duì)象counter的num屬性賦值給dummy
  • 然后做斷言判斷 dummy是否等于 0
  • 將 counter.num 賦值 7 ,然后 dummy 也變成了 7 !

這,,,讓我想到了什么??

這就是computed的嗎?

趕緊看下 computed 的測(cè)試用例?。?/p>

const value = reactive<{ foo?: number }>({})
const cValue = computed(() => value.foo)
expect(cValue.value).toBe(undefined)
value.foo = 1
expect(cValue.value).toBe(1)

哈哈哈

阿哈哈哈哈

hhhhhhhhhhhhhhhhhhhh

忍不住想仰天長(zhǎng)嘯!!

果然跟我猜想的一樣!??!我終于直到effect是個(gè)什么鬼了,顧名思義effect是副作用的意思,也就是說(shuō)它是響應(yīng)式副產(chǎn)品,每次觸發(fā)了 get 時(shí)收集effect,每次set時(shí)在觸發(fā)這些effects。這樣就可以做一些響應(yīng)式數(shù)據(jù)之外的一些事情了,比如計(jì)算屬性computed。

讓我們用effect實(shí)現(xiàn)一個(gè)computed 可能會(huì)更清晰一點(diǎn)

我就不寫(xiě)一些亂七八糟的判斷了,讓大家能夠看的更加清楚

function computed (fn) {
 let value = undefined
 const runner = effect(fn, {
  // 如果lazy不置為true的話,每次創(chuàng)建effect的時(shí)候都會(huì)立即執(zhí)行一次
  // 而我們要實(shí)現(xiàn)computed顯然是不需要的
  lazy: true
 })
 // 為什么要使用對(duì)象的形式,是因?yàn)槲覀冏詈笮枰玫絚omputed的值
 // 如果不用對(duì)象的 get 方法的話我們就需要手動(dòng)再調(diào)用一次 computed() 
 return {
  get value() {
   return runner()
  }
 }
}

// 使用起來(lái)是這樣的

const value = reactive({})
const cValue = computed(() => value.foo)
value.foo = 1

console.log(cValue.value) // 1

這也太簡(jiǎn)單了吧,那么重點(diǎn)來(lái)了,effect怎么實(shí)現(xiàn)的呢?

別著急,我們先捋一下邏輯

  1. 首先 如果 effect 回調(diào)內(nèi)有已響應(yīng)的對(duì)象被觸發(fā)了 get 時(shí),effect就應(yīng)該被儲(chǔ)存起來(lái)
  2. 然后,我們需要一個(gè)儲(chǔ)存effect的地方,在effect函數(shù)調(diào)用的時(shí)候就應(yīng)該把effect放進(jìn)這個(gè)儲(chǔ)存空間,在vue中使用的是一個(gè)數(shù)組activeReactiveEffectStack = []
  3. 再后,每個(gè)target被觸發(fā)的時(shí)候,都可能有多個(gè)effect,所以每個(gè)target需要有一個(gè)對(duì)應(yīng)的依賴(lài)收集器 deps,等到 set 時(shí)遍歷 deps 執(zhí)行 effect()
  4. 然而,這個(gè)依賴(lài)收集器 deps 不能放在 target 本身上,這樣會(huì)使數(shù)據(jù)看起來(lái)不是很簡(jiǎn)潔,還會(huì)存在多余無(wú)用的數(shù)據(jù),所以我們需要一個(gè) map 集合來(lái)儲(chǔ)存 target 跟 deps 的關(guān)系, 在vue中這個(gè)儲(chǔ)存集合叫 targetMap 。

幾個(gè)概念

track 追蹤器,在 get 時(shí)調(diào)用該函數(shù),將所有 get 的 target 跟 key 以及 effect 建立起對(duì)應(yīng)關(guān)系

// 比如 const react = reactive({a: { b: 2 })
// react.a 時(shí) target -> {a: { b: 2 } key -> a 
// targetMap 儲(chǔ)存了 target --> Map --> key --> Set --> dep --> effect 
// 當(dāng)調(diào)用 react.a.b.c.d.e 時(shí) depsMap
// {"a" => Set(1)} --> Set --> effect
// {"b" => Set(1)}
// {"c" => Set(1)}
// {"d" => Set(1)}
// {"e" => Set(1)}
export function track(target: any, key: string) {
 const effect = activeReactiveEffectStack[activeReactiveEffectStack.length - 1];
 if (effect) {
  let depsMap = targetMap.get(target);
  if (depsMap === void 0) {
   targetMap.set(target, (depsMap = new Map()));
  }
  let dep = depsMap.get(key!);
  if (!dep) {
   depsMap.set(key!, (dep = new Set()));
  }
  if (!dep.has(effect)) {
   dep.add(effect);
   effect.deps.push(dep);
  }
 }
}

trigger 觸發(fā)器,這個(gè)就比較好理解了,拿到target key下的對(duì)應(yīng)的所有 effect,然后遍歷執(zhí)行 effect()

export function trigger(target: any, key?: string | symbol) {
 const depsMap: any = targetMap.get(target);
 const effects: any = new Set()
 if (depsMap && depsMap.get(key)) {
  depsMap.get(key).forEach((dep: any) => {
   effects.add(dep)
  });
  effects.forEach((e: any) => e())
 }
}

effect 函數(shù)實(shí)現(xiàn)

// 暴露的 effect 函數(shù)
export function effect(
 fn: Function,
 options: any = EMPTY_OBJ
): any {
 if ((fn as any).isEffect) {
  fn = (fn as any).raw
 }
 const effect = createReactiveEffect(fn, options)
 // 如果不是 lazy,則會(huì)立即執(zhí)行一次
 if (!options.lazy) {
  effect()
 }
 return effect
}

// 創(chuàng)建 effect
function createReactiveEffect(
 fn: Function,
 options: any
): any {
 const effect = function effect(...args: any): any {
  return run(effect as any, fn, args)
 } as any
 effect.isEffect = true
 effect.active = true
 effect.raw = fn
 effect.scheduler = options.scheduler
 effect.onTrack = options.onTrack
 effect.onTrigger = options.onTrigger
 effect.onStop = options.onStop
 effect.computed = options.computed
 effect.deps = []
 return effect
}

// 執(zhí)行函數(shù),執(zhí)行完之后會(huì)將儲(chǔ)存的 effect 刪除
// 這是函數(shù) effect 的所有執(zhí)行,所經(jīng)歷的完整的聲明周期
function run(effect: any, fn: Function, args: any[]): any {
 if (!effect.active) {
  return fn(...args)
 }
 if (activeReactiveEffectStack.indexOf(effect) === -1) {
  try {
   activeReactiveEffectStack.push(effect)
   return fn(...args)
  } finally {
   activeReactiveEffectStack.pop()
  }
 }
}

一口氣寫(xiě)了這么多,最后總結(jié)一下。在大家看源碼的時(shí)候,如果發(fā)現(xiàn)有哪個(gè)地方無(wú)從下手的話,可以先從測(cè)試用例開(kāi)始看。因?yàn)闇y(cè)試用例可以很清楚的知道這個(gè)函數(shù)想要達(dá)到什么效果,然后從效果上想,為什么這么做,如果我自己寫(xiě)的話應(yīng)該怎么寫(xiě),這樣一點(diǎn)點(diǎn)就能揣摩出作者的意圖了。再根據(jù)源碼結(jié)合自己的想法你就能夠?qū)W到很多。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • vue3 teleport的使用案例詳解

    vue3 teleport的使用案例詳解

    這篇文章主要介紹了vue3 teleport的使用demo,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-11-11
  • Vue 開(kāi)發(fā)必須知道的36個(gè)技巧(小結(jié))

    Vue 開(kāi)發(fā)必須知道的36個(gè)技巧(小結(jié))

    這篇文章主要介紹了Vue 開(kāi)發(fā)必須知道的36個(gè)技巧(小結(jié)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • vue使用swiper.js重疊輪播組建樣式

    vue使用swiper.js重疊輪播組建樣式

    這篇文章主要為大家詳細(xì)介紹了vue使用swiper.js重疊輪播組建樣式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-11-11
  • vue3刪除過(guò)濾器的原因

    vue3刪除過(guò)濾器的原因

    去年,vue3出來(lái)了。增加了很多新功能,但是也刪掉了一些功能。比如刪掉了vue2中的過(guò)濾器filter功能。與此同時(shí),官方建議:用方法調(diào)用或計(jì)算屬性替換過(guò)濾器。本文將分析vue3刪除過(guò)濾器的原因及如何用其他方法實(shí)現(xiàn)過(guò)濾器的功能
    2021-05-05
  • vue.js簡(jiǎn)單配置axios的方法詳解

    vue.js簡(jiǎn)單配置axios的方法詳解

    axios是一個(gè)基于Promise 用于瀏覽器和 nodejs 的 HTTP 客戶(hù)端,下面這篇文章主要給大家介紹了關(guān)于vue.js簡(jiǎn)單配置axios的相關(guān)資料,需要的朋友們可以參考借鑒,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-12-12
  • vue自適應(yīng)布局postcss-px2rem詳解

    vue自適應(yīng)布局postcss-px2rem詳解

    這篇文章主要介紹了vue自適應(yīng)布局(postcss-px2rem)的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2022-05-05
  • vuejs2.0實(shí)現(xiàn)一個(gè)簡(jiǎn)單的分頁(yè)示例

    vuejs2.0實(shí)現(xiàn)一個(gè)簡(jiǎn)單的分頁(yè)示例

    本篇文章主要介紹了vuejs2.0實(shí)現(xiàn)一個(gè)簡(jiǎn)單的分頁(yè)示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-02-02
  • 詳解Vue.js中引入圖片路徑的幾種方式

    詳解Vue.js中引入圖片路徑的幾種方式

    這篇文章主要介紹了Vue.js中引入圖片路徑的幾種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • vue單頁(yè)面在微信下只能分享落地頁(yè)的解決方案

    vue單頁(yè)面在微信下只能分享落地頁(yè)的解決方案

    這篇文章主要介紹了vue單頁(yè)面在微信下只能分享落地頁(yè)的解決方案,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-04-04
  • vue實(shí)現(xiàn)左右滑動(dòng)效果實(shí)例代碼

    vue實(shí)現(xiàn)左右滑動(dòng)效果實(shí)例代碼

    左右滾動(dòng)的效果,在日常開(kāi)發(fā)中比較常見(jiàn),這篇文章主要給大家介紹了關(guān)于vue實(shí)現(xiàn)左右滑動(dòng)效果的相關(guān)資料,需要的朋友可以參考下
    2021-05-05

最新評(píng)論

芒康县| 荆门市| 紫金县| 札达县| 武夷山市| 沧源| 呼玛县| 田阳县| 东方市| 扎囊县| 琼中| 延吉市| 乌苏市| 邯郸县| 霍城县| 沾益县| 雅安市| 铁岭市| 陵水| 象州县| 洪湖市| 阿荣旗| 临夏县| 玛沁县| 阳新县| 上栗县| 双辽市| 日喀则市| 孟州市| 甘德县| 潜山县| 基隆市| 白玉县| 平泉县| 江口县| 苏尼特左旗| 二连浩特市| 卢龙县| 分宜县| 沙田区| 上思县|