2024.05.14

vue 响应式实现(5)

按这个结构改造

src/effect.js和03中一样

import { ITERATE_KEY, TrackOpTypes } from '../utils/eunm.js'

// effect/track.js
import { activeEffect, targetMap } from './effect.js'

/**
 * @type {boolean} 控制是否需要进行依赖收集
 */
let shouldTrack = true
export function pauseTracking() {
  shouldTrack = false
}
export function enableTracking() {
  shouldTrack = true
}

/**
 *  依赖收集器
 * @param target 原始对象
 * @param type 操作类型
 * @param key 操作的属性
 */
function track(target, type, key) {
  if (!shouldTrack) {
    return false
  }
  // 一层一层的查找,查找到后存储
  let propMap = targetMap.get(target)   if (!propMap) {    targetMap.set(target, (propMap = new Map()))   }
  // 如果是遍历的话,key 是 undefined
  if (type === TrackOpTypes.ITERATE) {    key = ITERATE_KEY  }
  let typeMap = propMap.get(key)   if (!typeMap) {    propMap.set(key, (typeMap = new Map()))   }
  // 根据 type 值查找对应的 set
  let depSet = typeMap.get(type)   if (!depSet) {    depSet = new Set()     typeMap.set(type, depSet)   }

  // set 集合找到的话 存储依赖
  if (!depSet.has(activeEffect)) {    depSet.add(activeEffect)     activeEffect.deps.push(depSet)   }}
export { track }

import { ITERATE_KEY, TriggerOpTypes, triggerTypeMap } from '../utils/eunm.js'
import { activeEffect, targetMap } from './effect.js'

src / trigger.js
/**
 *
 * @param target 原始对象
 * @param type 操作类型
 * @param key 操作的属性
 */

function trigger(target, type, key) {
  // 从设计好的数据结构里,一层一层的去找,找到对应的函数集合,然后全部执行一次
  const effectFns = getEffectFn(target, type, key)   if (!effectFns)
    return  for (const effectFn of effectFns) {    if (effectFn === activeEffect)
      continue    effectFn()   }}

/**
 * 根据 target type key 信息找到对应的依赖集合
 * @param target
 * @param type
 * @param key
 */
function getEffectFn(target, type, key) {  const propMap = targetMap.get(target)   if (!propMap)
    return  // 如果是新增或者删除,会涉及到触发额外的迭代
  const keys = [key]   if (type === TriggerOpTypes.ADD || type === TriggerOpTypes.DELETE) {    keys.push(ITERATE_KEY)   }

  const effectFns = new Set() // 存储依赖的函数  for (const key of keys) {    const typeMap = propMap.get(key)     if (!typeMap)
      continue
    const trackTypes = triggerTypeMap[type]     for (const trackType of trackTypes) {      const dep = typeMap.get(trackType)       if (!dep)
        continue      for (const effectFn of dep) {        effectFns.add(effectFn)       }    }  }  return effectFns}
export { trigger }

懒执行

传入的effect的回调会自动执行,修改这种行为

改造 effect.js,给传递参数

export function effect(fn, options = {}) {
  const { lazy } = options  const environment = () => {
    try {
      activeEffect = environment
      // 模拟真实的函数栈
      effectStack.push(environment)
      cleanup(environment)
      return fn()
    }
    finally {
      effectStack.pop()
      activeEffect = effectStack[effectStack.length - 1]
    }
  }
  environment.deps = [] // 记录该环境函数在哪些集合中使用

  if (!lazy) {    environment()   }  return environment}

如果传递了 lazy 返回函数交由控制权

手动派发更新

// effect.js
export function effect(fn, options = {}) {
  const { lazy } = options  const environment = () => {
    try {
      activeEffect = environment
      // 模拟真实的函数栈
      effectStack.push(environment)
      cleanup(environment)
      return fn()
    }
    finally {
      effectStack.pop()
      activeEffect = effectStack[effectStack.length - 1]
    }
  }
  environment.deps = [] // 记录该环境函数在哪些集合中使用
  environment.options = options  if (!lazy) {
    environment()
  }
  return environment
}
// trigger.js
function trigger(target, type, key) {
  //   从设计好的数据结构里,一层一层的去找,找到对应的函数集合,然后全部执行一次
  const effectFns = getEffectFn(target, type, key)
  if (!effectFns)
    return
  for (const effectFn of effectFns) {
    if (effectFn === activeEffect)
      continue
    // 如果传递了 scheduler ,交由外部手动更新
    if (effectFn.options && effect.options.scheduler) {      effect.options.scheduler(effectFn)     }    effectFn()
  }
}