<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          為啥面試官總喜歡問computed是咋實(shí)現(xiàn)的?

          共 7610字,需瀏覽 16分鐘

           ·

          2023-10-16 20:49

          大廠技術(shù)  高級(jí)前端  Node進(jìn)階

          點(diǎn)擊上方 程序員成長指北,關(guān)注公眾號(hào)

          回復(fù)1,加入高級(jí)Node交流群


          而對(duì)于每天都在用的計(jì)算屬性(computed),我猜你肯定也想窺探其奧妙與原理對(duì)吧!走起!

          從computed的特性出發(fā)

          computed最耀眼的幾個(gè)特性是啥?

          1. 依賴追蹤

          import { reactive, computed } from 'vue'

          const state = reactive({
            a1,
            b2,
            c3,
          })
          const sum = computed(() => {
            return state.a + state.b
          })

          我們定義了一個(gè)響應(yīng)式數(shù)據(jù)state和一個(gè)計(jì)算屬性sum, Vue會(huì)自動(dòng)追蹤sum依賴的數(shù)據(jù)state.astate.b,并建立相應(yīng)的依賴關(guān)系。

          也就是只有state.astate.b發(fā)生變化的時(shí)候,sum才會(huì)重新計(jì)算而state.c任由它怎么變,sum都將絲毫不受影響。

          2. 緩存

          還是上面的例子,如果state.astate.b打死都不再改變值了,那么我們讀取sum的時(shí)候,它將會(huì)返回上一次計(jì)算的結(jié)果,而不是重新計(jì)算。

          3. 懶計(jì)算

          這個(gè)特性比較容易被忽略,簡單地說只有計(jì)算屬性真正被使用(讀取)的時(shí)候才會(huì)進(jìn)行計(jì)算,否則咱就僅僅是定義了一個(gè)變量而已。

          import { reactive, computed } from 'vue'

          const state = reactive({
            a1,
            b2,
            c3
          })

          const sum = computed(() => {
            console.log('執(zhí)行計(jì)算')
            return state.a + state.b
          })

          setTimeout(() => {
            // 沒有讀取sum.value之前,sum不會(huì)進(jìn)行計(jì)算
            console.log('1-sum', sum.value)
            // 我們改變了a的值,但是sum并不會(huì)立刻進(jìn)行計(jì)算
            state.a = 4

            setTimeout(() => {
              // 而是要等到再次讀取的時(shí)候才會(huì)觸發(fā)重新計(jì)算
              console.log('2-sum', sum.value)
            }, 1000)
          }, 1000)



          挨個(gè)實(shí)現(xiàn)computed特性

          1. 懶計(jì)算

          我們依舊圍繞effect函數(shù)來搞事情,到目前為止,effect注冊的回調(diào)都是立刻執(zhí)行。

          const state = reactive({
            a1,
            b2,
            c3
          })
          // 有沒有很像計(jì)算屬性的感覺
          const sum = effect(() => {
            console.log('執(zhí)行計(jì)算'// 立刻被打印
            const value = state.a + state.b
            return value
          })

          console.log(sum) // undefined

          想要實(shí)現(xiàn)computed的懶執(zhí)行,咱們可以參考上篇文章Vue3:原來你是這樣的“異步更新”的思路,添加一個(gè)額外的參數(shù)lazy

          它要實(shí)現(xiàn)的功能是:如果傳遞了lazytrue,副作用函數(shù)將不會(huì)立即執(zhí)行,而是將執(zhí)行的時(shí)機(jī)交還給用戶,由用戶決定啥時(shí)候執(zhí)行。

          當(dāng)然啦!回調(diào)的結(jié)果我們也應(yīng)該一并返回(例如上面的value值)

          你能想象,我們僅僅需要改造幾行代碼就能離computed近了一大步。

          const effect = function (fn, options = {}{
            const effectFn = () => {
              // ... 省略
              // 新增res存儲(chǔ)fn執(zhí)行的結(jié)果
              const res = fn()
              // ... 省略
              // 新增返回結(jié)果
              return res
            }
            // ... 省略
            // 新增,只有l(wèi)azy不為true時(shí)才會(huì)立即執(zhí)行
            if (!options.lazy) {
              effectFn()
            }
            // 新增,返回副作用函數(shù)讓用戶執(zhí)行
            return effectFn
          }

          測試一波

          const state = reactive({
            a1,
            b2,
            c3,
          });
          // 有沒有很像計(jì)算屬性的感覺
          const sum = effect(() => {
            console.log("執(zhí)行計(jì)算"); // 調(diào)用sum函數(shù)后被打印
            const value = state.a + state.b;
            return value;
          }, {
            lazytrue
          });
          // 不執(zhí)行sum函數(shù),effect注冊的回調(diào)將不會(huì)執(zhí)行
          console.log(sum()); // 3

          2. 依賴追蹤

          咱們初步實(shí)現(xiàn)了懶執(zhí)行的特性,為了更像computed一點(diǎn),我們需要封裝一個(gè)函數(shù)。

          function computed (getter{
            const effectFn = effect(getter, {
              lazytrue,
            })

            const obj = {
              get value () {
                return effectFn()
              }
            }

            return obj
          }

          這就有點(diǎn)那么味道啦!

          測試一波

          可以看到computed只會(huì)依賴state.astate.b,而不會(huì)依賴state.c,這得益于我們前面幾篇文章實(shí)現(xiàn)的響應(yīng)式系統(tǒng),所以到了計(jì)算屬性這里,我們不用改動(dòng)任何代碼,天然就支持。

          不過還是有點(diǎn)小問題,我們讀取了兩次sum.value,sum卻被執(zhí)行了兩次,這和computed緩存的特性就不符了。

          別急,馬上就要實(shí)現(xiàn)了這個(gè)最重要的特性了。

          const state = reactive({
            a1,
            b2,
            c3
          })

          const sum = computed(() => {
            console.log('執(zhí)行計(jì)算')
            return state.a + state.b
          })

          console.log(sum.value)
          console.log(sum.value)

          3. 緩存

          回顧一下computed的緩存特性:

          1. 只有當(dāng)其依賴的東西發(fā)生變化了才需要重新計(jì)算
          2. 否則就返回上一次執(zhí)行的結(jié)果。

          為了緩存上一次計(jì)算的結(jié)果,咱們需要定義一個(gè)value變量,現(xiàn)在的關(guān)鍵是怎么才能知道其依賴的數(shù)據(jù)發(fā)生變化了呢?

          function computed (getter{
            const effectFn = effect(getter, {
              lazytrue,
            })
            let value
            let dirty = true

            const obj = {
              get value () {
                // 2. 只有數(shù)據(jù)發(fā)生變化了才去重新計(jì)算
                if (dirty) {
                  value = effectFn()
                  dirty = false
                }

                return value
              }
            }

            return obj
          }

          測試一波

          const state = reactive({
            a1,
            b2,
            c3
          })

          const sum = computed(() => {
            console.log('執(zhí)行計(jì)算')
            return state.a + state.b
          })

          console.log(sum.value) // 3
          console.log(sum.value) // 3

          state.a = 4

          console.log(sum.value) // 3 答案是錯(cuò)誤的

          寄上任務(wù)調(diào)度

          不得不說,任務(wù)調(diào)度實(shí)在太強(qiáng)大了,不僅僅可以實(shí)現(xiàn)數(shù)組的異步批量更新、在computedwatch中也是必不可少的。

          function computed (getter{
            const effectFn = effect(getter, {
              lazytrue,
              // 數(shù)據(jù)發(fā)生變化后,不執(zhí)行注冊的回調(diào),而是執(zhí)行scheduler
              scheduler () {
                // 數(shù)據(jù)發(fā)生了變化后,則重新設(shè)置為dirty,那么下次就會(huì)重新計(jì)算
                dirty = true
              }
            })
            let value
            let dirty = true

            const obj = {
              get value () {
                // 2. 只有數(shù)據(jù)發(fā)生變化了才去重新計(jì)算
                if (dirty) {
                  value = effectFn()
                  dirty = false
                }

                return value
              }
            }

            return obj
          }

          測試一波

          const state = reactive({
            a1,
            b2,
            c3
          })

          const sum = computed(() => {
            console.log('執(zhí)行計(jì)算')
            return state.a + state.b
          })

          console.log(sum.value) // 3
          console.log(sum.value) // 3

          state.a = 4

          console.log(sum.value) // 3 答案是錯(cuò)誤的

          完美!!!這下面試官再也難不倒我了!!!

          結(jié)尾

          Node 社群

               
               


          我組建了一個(gè)氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對(duì)Node.js學(xué)習(xí)感興趣的話(后續(xù)有計(jì)劃也可以),我們可以一起進(jìn)行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。

             “分享、點(diǎn)贊在看” 支持一下

          瀏覽 591
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  91亚洲嫩 | 精品区一二三 | 欧洲精品成人AV在线蜜芽 | 97超碰人 | 欧美V日韩V|