Record--Why do interviewers always like to ask how computed is implemented?

Here I will share with you some of the knowledge I have summarized on the Internet, I hope it will be helpful to everyone

Starting from the characteristics of computed

computedWhat are the most dazzling features?

1. Dependency Tracking

import { reactive, computed } from 'vue'

const state = reactive({
  a: 1,
  b: 2,
  c: 3,
})
const sum = computed(() => {
  return state.a + state.b
})

We define a responsive data stateand a computed property , and sumVue will automatically track sumthe dependent data and establish corresponding dependencies.state.astate.b

That is, only state.awhen state.bthe sum changes, it sumwill be recalculated, and state.cno matter how it changes, sumit will not be affected at all.

2. Cache

Still the above example, if state.athe state.bvalue is no longer changed after being killed, then sumwhen we read it, it will return the result of the last calculation instead of recalculating.

3. Lazy computing

This feature is relatively easy to be ignored. Simply put, it will only be calculated when the calculated property is actually used (read), otherwise we just define a variable.

import { reactive, computed } from 'vue'

const state = reactive({
  a: 1,
  b: 2,
  c: 3
})

const sum = computed(() => {
  console.log('执行计算')
  return state.a + state.b
})

setTimeout(() => {
  // 没有读取sum.value之前,sum不会进行计算
  console.log('1-sum', sum.value)
  // 我们改变了a的值,但是sum并不会立刻进行计算
  state.a = 4

  setTimeout(() => {
    // 而是要等到再次读取的时候才会触发重新计算
    console.log('2-sum', sum.value)
  }, 1000)
}, 1000)

Implement computed features one by one

1. Lazy computing

We still effectdo things around functions, and so far, effectregistered callbacks are executed immediately.

const state = reactive({
  a: 1,
  b: 2,
  c: 3
})
// 有没有很像计算属性的感觉
const sum = effect(() => {
  console.log('执行计算') // 立刻被打印
  const value = state.a + state.b
  return value
})

console.log(sum) // undefined

If you want to implement computedlazy execution, we can refer to the previous article Vue3: It turns out that you have such an "asynchronous update" idea, adding an additional parameter lazy.

lazyThe function it wants to achieve is: if the value is passed true, the side effect function will not be executed immediately, but the timing of execution will be returned to the user, and the user decides when to execute it.

of course! We should also return the result of the callback (such as the value above)

As you can imagine, we only need to modify a few lines of code to get computeda big step closer.

const effect = function (fn, options = {}) {
  const effectFn = () => {
    // ... 省略
    // 新增res存储fn执行的结果
    const res = fn()
    // ... 省略
    // 新增返回结果
    return res
  }
  // ... 省略
  // 新增,只有lazy不为true时才会立即执行
  if (!options.lazy) {
    effectFn()
  }
  // 新增,返回副作用函数让用户执行
  return effectFn
}

test wave

const state = reactive({
  a: 1,
  b: 2,
  c: 3,
});
// 有没有很像计算属性的感觉
const sum = effect(() => {
  console.log("执行计算"); // 调用sum函数后被打印
  const value = state.a + state.b;
  return value;
}, {
  lazy: true
});
// 不执行sum函数,effect注册的回调将不会执行
console.log(sum()); // 3

2. Dependency Tracking

We have initially implemented the feature of lazy execution. In order to be computedmore similar, we need to encapsulate a function.

function computed (getter) {
  const effectFn = effect(getter, {
    lazy: true,
  })

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

  return obj
}

This is a bit so flavorful!

test wave

It can be seen computedthat it only depends on state.aand state.b, but not on state.c. This is due to the responsive system implemented in our previous articles, so when it comes to computing properties, we don’t need to change any code, and it is naturally supported.

However, there is still a small problem. We read it twice sum.value, but the sum is executed twice, which computeddoes not match the characteristics of the cache.

Don't worry, this most important feature will be implemented soon.

const state = reactive({
  a: 1,
  b: 2,
  c: 3
})

const sum = computed(() => {
  console.log('执行计算')
  return state.a + state.b
})

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

3. Cache

Review computedthe caching features:

  1. It needs to be recalculated only when the things it depends on change
  2. Otherwise, the result of the last execution is returned.

In order to cache the result of the last calculation, we need to define a value variable. The key now is how to know that the data it depends on has changed?

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

  const obj = {
    get value () {
      // 2. 只有数据发生变化了才去重新计算
      if (dirty) {
        value = effectFn()
        dirty = false
      }

      return value
    }
  }

  return obj
}
test wave
const state = reactive({
  a: 1,
  b: 2,
  c: 3
})

const sum = computed(() => {
  console.log('执行计算')
  return state.a + state.b
})

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

state.a = 4

console.log(sum.value) // 3 答案是错误的

Send task scheduler

It has to be said that task scheduling is so powerful that it can not only realize asynchronous batch update of arrays, but also is essential in computedand .watch

function computed (getter) {
  const effectFn = effect(getter, {
    lazy: true,
    // 数据发生变化后,不执行注册的回调,而是执行scheduler
    scheduler () {
      // 数据发生了变化后,则重新设置为dirty,那么下次就会重新计算
      dirty = true
    }
  })
  let value
  let dirty = true

  const obj = {
    get value () {
      // 2. 只有数据发生变化了才去重新计算
      if (dirty) {
        value = effectFn()
        dirty = false
      }

      return value
    }
  }

  return obj
}

test wave

const state = reactive({
  a: 1,
  b: 2,
  c: 3
})

const sum = computed(() => {
  console.log('执行计算')
  return state.a + state.b
})

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

state.a = 4

console.log(sum.value) // 3 答案是错误的

Perfect! ! ! Now the interviewer can no longer trouble me! ! !

This article is reproduced in:

https://juejin.cn/post/7259405321020424251

If it is helpful to you, you are welcome to pay attention. I will update the technical documents regularly, and we will discuss and learn together and make progress together.

 

Guess you like

Origin blog.csdn.net/qq_40716795/article/details/131930134