IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> Vue 3.0 源码计算属性 Computed的实现 -> 正文阅读

[JavaScript知识库]Vue 3.0 源码计算属性 Computed的实现

我们来看下 计算属性源码是怎么实现的呢?

参数 getterOrOptions 是判断是写的
第一种是 函数只有getter
computed(()=>{
});
第二种 是 对象 有get 跟set
computed({
get: function () {},
set: function (newValue) {console.log()}
});

  function computed(getterOrOptions, debugOptions, isSSR = false) {
      let getter;
      let setter;
      // 这里则是做的判断
      const onlyGetter = isFunction(getterOrOptions);
      if (onlyGetter) {
          getter = getterOrOptions;
          // 不允许设置 setter
          setter = () => {
                  console.warn('Write operation failed: computed value is readonly');
              }
              ;
      }
      else {
          // 如果是对象的写法 就去拿到它的get 跟 set
          getter = getterOrOptions.get;
          setter = getterOrOptions.set;
      }
      // 底层是通过一个 ComputedRefImpl 类来实现的
      const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR);
      if (debugOptions && !isSSR) {
          cRef.effect.onTrack = debugOptions.onTrack;  // onTrack 跟 onTrigger 使用户可以穿进来做debug 测试用的 一般不会用到
          cRef.effect.onTrigger = debugOptions.onTrigger;
      }
      return cRef;
  }

ComputedRefImpl 的实现

  class ComputedRefImpl {
      constructor(getter, _setter, isReadonly, isSSR) {
          this._setter = _setter;
          this.dep = undefined;
          this.__v_isRef = true;
          // 这个是 判断值是不是 脏值 模式是脏值 用来判断需不需要更新
          this._dirty = true;
          // 计算属性也是通过 ReactiveEffect 来实现监听的
          // 只不过 穿了一个调度器
          this.effect = new ReactiveEffect(getter, () => {
          	  // 判断值 是否是脏值 然后做更新操作
              if (!this._dirty) {
                  this._dirty = true;
                  triggerRefValue(this);
              }
          });
          this.effect.computed = this;
          this.effect.active = this._cacheable = !isSSR;
      }
      // 这个的 get 是为了属性拿值的时候做监听 所以
      const aaa = computed(()=>{
      	return state.name;
	});
	// 这个是拿值的操作 就会被监听到 
	// aaa.value
	// 同样的 set 也是 被设置的时候 也会监听到, 但是计算属性用到 set的情况都很少
	// aaa.value = 111;
      get value() {
          const self = toRaw(this);
          // 这个是通过 get 值的时候去 做收集
          trackRefValue(self);
          if (self._dirty || !self._cacheable) {
              self._dirty = false;
              self._value = self.effect.run();
          }
          return self._value;
      }
      set value(newValue) {
          this._setter(newValue);
      }
  }

triggerRefValue 的实现

  function triggerRefValue(ref, newVal) {
      ref = toRaw(ref);
      if (ref.dep) {
          {
              triggerEffects(ref.dep, {
                  target: ref,
                  type: "set" /* TriggerOpTypes.SET */,
                  key: 'value',
                  newValue: newVal
              });
          }
      }
  }

  function triggerEffects(dep, debuggerEventExtraInfo) {
      // spread into array for stabilization
      const effects = isArray(dep) ? dep : [...dep];
      // 判断是不是计算属性
      for (const effect of effects) {
          if (effect.computed) {
              triggerEffect(effect, debuggerEventExtraInfo);
          }
      }
      for (const effect of effects) {
          if (!effect.computed) {
              triggerEffect(effect, debuggerEventExtraInfo);
          }
      }
  }
  
  function triggerEffect(effect, debuggerEventExtraInfo) {
      if (effect !== activeEffect || effect.allowRecurse) {
           // 这里是 判断如果有 自己的调度函数 就执行调度函数 没有就自己执行run函数
          if (effect.scheduler) {
              effect.scheduler();
          }
          else {
              effect.run();
          }
      }
  }

trackRefValue的实现

  function trackRefValue(ref) {
      if (shouldTrack && activeEffect) {
          ref = toRaw(ref);
          {
              trackEffects(ref.dep || (ref.dep = createDep()), {
                  target: ref,
                  type: "get" /* TrackOpTypes.GET */,
                  key: 'value'
              });
          }
      }
  }
  
  function trackEffects(dep, debuggerEventExtraInfo) {
      let shouldTrack = false;
      // 这里做了一些性能的优化 先去找 有没有 有的话就不做收集了
      if (effectTrackDepth <= maxMarkerBits) {
          if (!newTracked(dep)) {
              dep.n |= trackOpBit; // set newly tracked
              shouldTrack = !wasTracked(dep);
          }
      }
      else {
          // Full cleanup mode.
          shouldTrack = !dep.has(activeEffect);
      }
      // 这个是判断是不是该收集 这个effect
      if (shouldTrack) {
          dep.add(activeEffect);
          activeEffect.deps.push(dep);
          // 这个是 你实例上有没有写这个debug方法 有了就做对应的处理
          if (activeEffect.onTrack) {
              activeEffect.onTrack(Object.assign({ effect: activeEffect }, debuggerEventExtraInfo));
          }
      }
  }

计算属性的原理 简单来说 就是 通过effect 的ReactiveEffect 的getter 来做依赖收集,主要是去监听 依赖的响应值有没有变化,如果变化了就拿到变化了的effect通过track去做收集, 然后去执行调度器的这个方法, 从而通过trigger函数去更新值, trigger 就去拿到依赖的值 做每一个收集的effect的run方法 从而达到更新值

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-09-30 00:43:36  更:2022-09-30 00:43:45 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 5:46:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码