当前位置: 首页 > article >正文

《Vue进阶教程》第二十四课:优化

  往期内容:

《Vue进阶教程》第十三课:实现依赖收集

《Vue进阶教程》第十四课:改进桶结构

《Vue进阶教程》第十五课:深入完善响应式系统之模块化

《Vue进阶教程》第十六课:深入完善响应式系统之单例模式

《Vue进阶教程》第十七课:支持分支切换

《Vue进阶教程》第十八课:避免死循环

《Vue进阶教程》第十九课:computed初步实现

《Vue进阶教程》第二十课:lazy懒执行

《Vue进阶教程》第二十一课:支持缓存

《Vue进阶教程》第二十二课:自定义更新(调度器)

《Vue进阶教程》第二十三课:渲染计算属性的结果

1) 封装

由于computed函数最终会返回一个对象.

可以考虑将返回的对象封装成ComputedRefImpl的实例

class ComputedRefImpl {
  constructor(fn) {
    this._value = null // 缓存
    this._dirty = true // 标识
    this.effect = new RectiveEffect(fn, () => {
      if (!this._dirty) this._dirty = true
      trigger(this, 'value')
    })
  }
  get value() {
    // 收集当前计算属性依赖的副作用函数
    track(obj, 'value')  
    
    if (this._dirty) {
      this._value = this.effect.run()
      this._dirty = false
    }
    return this._value
  }
}
// 这里先只考虑fn是函数的情况
function computed(fn) {
  return new ComputedRefImpl(fn)
}

2) 扩展

考虑到计算属性是可以支持两种配置的. 进一步扩展支持配置(getter/setter)

class ComputedRefImpl {
  constructor(getter, setter) {
    this._value = null // 缓存
    this._dirty = true // 标识
    this.effect = new RectiveEffect(getter, () => {
      if (!this._dirty) this._dirty = true
      trigger(this, 'value')
    })
    this.setter = setter
  }
  get value() {
    track(this, 'value')
    if (this._dirty) {
      this._value = this.effect.run()
      this._dirty = false
    }
    return this._value
  }
  set value(newVal) {
    return this.setter(newVal)
  }
}

function computed(getterOrOptions) {
  let getter
  let setter
  if (typeof getterOrOptions == 'function') {
    getter = getterOrOptions
    setter = () => {
      console.warn('no setter')
    }
  } else {
    getter = getterOrOptions.get
    setter = getterOrOptions.set
  }
  return new ComputedRefImpl(getter, setter)
}

3) 解耦复用

在收集依赖时, 不能很好的观察到当前计算属性依赖的副作用函数.

可以考虑给ComputedRefImpl加一个dep属性, 用来保存哪些副作用函数引用了当前计算属性

而且, 在调用tracktrigger时, 必须要传入两个参数. 这里我们人为创造了一个value. 这种方式不够优雅

考虑对tracktrigger进一步解耦

class ComputedRefImpl {
  constructor(getter, setter) {
    this._value = null // 缓存
    this._dirty = true // 标识
    this.dep = new Set()
    this.effect = new RectiveEffect(getter, () => {
      if (!this._dirty) this._dirty = true
      triggerEffects(this.dep)
    })
    this.setter = setter
  }
  get value() {
    trackEffects(this.dep)
    if (this._dirty) {
      this._value = this.effect.run()
      this._dirty = false
    }
    return this._value
  }
  set value(newVal) {
    return this.setter(newVal)
  }
}

实现trackEffects

function trackEffects(dep) {
  // 只有当activeEffect有值时, 才需要收集依赖
  if (!activeEffect) return

  dep.add(activeEffect)
  activeEffect.deps.push(dep)
}

实现triggerEffects

function triggerEffects(dep) {
  if (!dep) return

  const effects = [...dep]
  effects.forEach(effect => {
    if (effect !== activeEffect) {
      if (effect.scheduler) {
        effect.scheduler()
      } else {
        effect.run()
      }
    }
  })
}


http://www.kler.cn/a/457331.html

相关文章:

  • 智联视频超融合平台:电力行业的智能守护者
  • 职场常用Excel基础04-二维表转换
  • 使用java语言,自定义redistemplate
  • 供需平台信息发布付费查看小程序系统开发方案
  • 生成对抗网络 (Generative Adversarial Network, GAN) 算法MNIST图像生成任务及CelebA图像超分辨率任务
  • 游戏引擎学习第69天
  • c++ 里 常量转换 const_cast < T > ,要给模板参数 T 传递什么类型呢?
  • iClient3D for Cesium 加载shp数据并拉伸为白模
  • Node.js 工具:在 Windows 11 中配置 Node.js 的详细步骤
  • 影刀进阶应用 | 知乎发布想法
  • EMQX5.X版本性能配置调优参数
  • NSSCTF-web刷题
  • 爬虫入门二 beautifulsoup
  • 一个通用的居于 OAuth2的API集成方案
  • 解密MQTT协议:从QOS到消息传递的全方位解析
  • Element分阶段逐步升级
  • (计算机毕设)基于SpringBoot+Vue的在线音乐平台
  • K8s Flannel vs Calico:基于 L2 与 L3 的 CNI 之战(一)
  • DINO: 基于双向知识蒸馏的视觉智能自学习方法
  • 设计模式之状态模式:自动售货机的喜怒哀乐
  • 通过 python 获取金融数据-akshare
  • ESP32_H2(IDF)学习系列-ADC模数转换(单次转换)
  • 将 ASP.NET Core 应用程序的日志保存到 D 盘的文件中 (如 Serilog)
  • 【2025最新计算机毕业设计】基于SpringBoot+Vue体育资讯系统(可定制,项目包括源码、文档、远程调试、免费答疑至毕业】
  • 12.28作业
  • Etcd静态分布式集群搭建