返回顶部
首页 > 资讯 > 前端开发 > JavaScript >Vuecomputed实现原理深入讲解
  • 761
分享到

Vuecomputed实现原理深入讲解

Vuecomputed用法Vuecomputed的作用Vuecomputed 2022-11-13 18:11:31 761人浏览 薄情痞子
摘要

目录定义依赖收集依赖触发依赖总结在从Vue(v2.7.10)源码分析vue是如何收集依赖和触发依赖这篇文章中我们讲了vue是怎么收集依赖的。其中computed的实现原理和这个密切相

在从Vue(v2.7.10)源码分析vue是如何收集依赖和触发依赖这篇文章中我们讲了vue是怎么收集依赖的。其中computed的实现原理和这个密切相关,接下来我们看看computed的实现原理。

基础代码如下:

<template>
  <div>
    {{getA}}
    <button @click="addModule">新增</button>
  </div>
</template>
<script>
export default {
  name: "TestwebpackTest",
  mounted() {
    console.log(this);
  },
  data() {
    return {
      num: 1,
      a:2
    };
  },
  computed:{
    getA(){
      return this.a
    }
  },  
  methods: {
    addModule() {
      this.a++;
    }
  }
};
</script>
<style lang="sCSS">
div {
  .test {
    width: 10px;
    height: 15px;
    background-color: blue;
  }
}
</style>

定义依赖

直接上代码,在执行render函数实例化TestWEBpackTest组件的时候会执行下面的方法:

Vue.extend = function (extendOptions) {
    ...
    if (Sub.options.computed) {
        initComputed(Sub);
    }
    ...
};

在该方法中会执行initComputed方法,该方法遍历computed并执行defineComputed方法:

function initComputed(Comp) {
    var computed = Comp.options.computed;
    for (var key in computed) {
        defineComputed(Comp.prototype, key, computed[key]);
    }
}
var sharedPropertyDefinition = {
      enumerable: true,
      configurable: true,
      get: noop,
      set: noop
  };
// key: "getA"  target: Vue {constructor: ƒ} userDef:ƒ getA()
function defineComputed(target, key, userDef) {
      var shouldCache = !isServerRendering(); // true
      if (isFunction(userDef)) {
          sharedPropertyDefinition.get = shouldCache
              ? createComputedGetter(key)
              : createGetterInvoker(userDef);
          sharedPropertyDefinition.set = noop;
      }
      else {
         ...
      }
     ...
      Object.defineProperty(target, key, sharedPropertyDefinition);
  }

主要执行了createComputedGetter方法设置computed函数getA的get方法:

// key: "getA"
function createComputedGetter(key) {
      return function computedGetter() {
          var watcher = this._computedWatchers && this._computedWatchers[key];
          if (watcher) {
              if (watcher.dirty) {
                  watcher.evaluate();
              }
              if (Dep.target) {
                  if (Dep.target.onTrack) {
                      Dep.target.onTrack({
                          effect: Dep.target,
                          target: this,
                          type: "get" ,
                          key: key
                      });
                  }
                  watcher.depend();
              }
              return watcher.value;
          }
      };
  }

该方法执行过程在收集依赖部分分析。返回该函数后执行Object.defineProperty(target, key, sharedPropertyDefinition),给当前的vm设置getA响应式。至此设置响应完毕。

收集依赖

收集依赖发生在执行组件渲染过程,会通过_vm.getA触发computed的get方法。

var render = function render() {
  var _vm = this,
    _c = _vm._self._c
  return _c("div", [
    _vm._v("\n  " + _vm._s(_vm.getA) + "\n  "),
    _c("button", { on: { click: _vm.addModule } }, [_vm._v("新增")]),
  ])
}

会获取当前的computed函数生成的watcher,继续执行watcher.evaluate()方法:

var watcher = this._computedWatchers && this._computedWatchers[key];
 if (watcher) {
     if (watcher.dirty) { // true
         watcher.evaluate();
     }
     if (Dep.target) {
         if (Dep.target.onTrack) {
             Dep.target.onTrack({
                 effect: Dep.target,
                 target: this,
                 type: "get" ,
                 key: key
             });
         }
         watcher.depend();
     }
     return watcher.value;
 }
Watcher.prototype.evaluate = function () {
     this.value = this.get();
     this.dirty = false;
 };

调用当前watcher的get方法,首先设置当前的Dep.target为当前的watcher,然后执行this.getter方法,该方法为getA方法,相当于执行该函数。

Watcher.prototype.get = function () {
     pushTarget(this);
     var value;
     var vm = this.vm;
     try {
         value = this.getter.call(vm, vm);
     }
     catch (e) {
        ...
     }
     finally {
         // "touch" every property so they are all tracked as
         // dependencies for deep watching
         if (this.deep) {
             traverse(value);
         }
         popTarget();
         this.cleanupDeps();
     }
     return value;
 };

由于依赖于a变量,所以会触发a变量的get方法,并执行dep.depend方法

var value = getter ? getter.call(obj) : val;
if (Dep.target) {
     {
         dep.depend({
             target: obj,
             type: "get" ,
             key: key
         });
     }
     ...
 }
 return isRef(value) && !shallow ? value.value : value;
 ...
Dep.prototype.depend = function (info) {
   if (Dep.target) {
        Dep.target.aDDDep(this);
        if (info && Dep.target.onTrack) {
            Dep.target.onTrack(__assign({ effect: Dep.target }, info));
        }
    }
};
...
Watcher.prototype.addDep = function (dep) {
    var id = dep.id;
    if (!this.newDepIds.has(id)) {
        this.newDepIds.add(id);
        this.newDeps.push(dep);
        if (!this.depIds.has(id)) {
            dep.addSub(this);
        }
    }
};

当前的Dep.target是getA的watcher实例,a变量会找到订阅者(getA的watcher),并在该watcher的newDeps里添加该变量的dep(this.newDeps.push(dep)),然后该变量会把getA的watcher加入自己的依赖(dep.addSub(this))。从而建立了getA和num之间的联系。接下来执行popTarget()和this.cleanupDeps()将当前Dep.target置为组件的watcher,然后newDeps的值赋给deps。至此watcher.evaluate()执行完后this.getter.call(vm, vm)执行完毕,返回a的value。

触发依赖

当变量发生变化时会触发该变量的set方法:

function ReactiveSetter(newVal) {
    var value = getter ? getter.call(obj) : val;
     ...
     else if (!shallow && isRef(value) && !isRef(newVal)) {
         value.value = newVal;
         return;
     }
     else {
         val = newVal;
     }
     childOb = !shallow && observe(newVal, false, mock);
     {
         dep.notify({
             type: "set" ,
             target: obj,
             key: key,
             newValue: newVal,
             oldValue: value
         });
     }
 }

主要执行dep.notify方法:

Dep.prototype.notify = function (info) {
    // stabilize the subscriber list first
    var subs = this.subs.slice();
    ...
    for (var i = 0, l = subs.length; i < l; i++) {
        ...
        subs[i].update();
    }
};
Watcher.prototype.update = function () {
   
    if (this.lazy) {
        this.dirty = true;
    }
    else if (this.sync) {
        this.run();
    }
    else {
        queueWatcher(this);
    }
};

主要执行subs[i].update()方法,当前的变量a有两个dep,computed的lazy为true不会继续执行。第二个dep为组件的watcher,执行该watcher的update方法重新渲染刷新页面。

总结

  • 在组件实例化的时候会遍历computed设置computed的get方法并设置Dep.target为当前computed的watcher。
  • 在执行渲染模板方法的时候会触发该computed的get方法。
  • 会执行computed函数,当该函数里获取变量时会触发变量的get方法。该变量会通过Dep.target获取当前的watcher并添加自己的dep(相当于记录了订阅了哪些变量),也就是说获取变量的时候会订阅该变量,该变量也会在自己的依赖dep添加watcher(记录订阅者,发生变化时会通知订阅者)。
  • 当前变量发生改变时会循环触发该变量的dep的update方法刷新页面。其中computed方法由于已经获取最新值所以只需要执行组件的update方法。

到此这篇关于Vue computed实现原理深入讲解的文章就介绍到这了,更多相关Vue computed内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Vuecomputed实现原理深入讲解

本文链接: https://lsjlt.com/news/169887.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Vuecomputed实现原理深入讲解
    目录定义依赖收集依赖触发依赖总结在从vue(v2.7.10)源码分析vue是如何收集依赖和触发依赖这篇文章中我们讲了vue是怎么收集依赖的。其中computed的实现原理和这个密切相...
    99+
    2022-11-13
    Vue computed用法 Vue computed的作用 Vue computed
  • VueComputed底层原理深入探究
    今天面了家小公司,上来直接问 computed 底层原理,面试官是这样问的,data 中定义了 a 和 b 变量。computed 里面定义了 c 属性,c 的结果依赖与 a 和 b...
    99+
    2024-04-02
  • 深入讲解Socket原理
    目录关于TCP/IP、UDP、Socket什么是TCP/IP、UDP?Socket在哪里呢?Socket是什么呢?你会使用它们吗?1、网络中进程之间如何通信?2、什么是Socket?...
    99+
    2024-04-02
  • Golangsync.Map原理深入分析讲解
    目录GO语言内置的mapsync.Mapsync.Map原理分析sync.Map的结构查找新增和更新删除GO语言内置的map go语言内置一个map数据结构,使用起来非常方便,但是它...
    99+
    2022-12-17
    Go sync.Map Golang sync.Map原理
  • Vuewatch原理源码层深入讲解
    目录添加依赖触发依赖总结由于我在从源码看vue(v2.7.10)的computed的实现原理中详细的讲解过computed的实现,本篇跟computed的原理类似。我就带大家简单分析...
    99+
    2022-11-13
    Vue watch原理 Vue watch的作用
  • ReactHooks核心原理深入分析讲解
    目录Hooks闭包开始动手实现将useState应用到组件中过期闭包模块模式实现useEffect支持多个HooksCustom Hooks重新理解Hooks规则React Hook...
    99+
    2022-12-17
    React Hooks React Hooks原理
  • 深入了解vuex的实现原理
    当面试被问vuex的实现原理,你要怎么回答?下面本篇文章就来带大家深入了解一下vuex的实现原理,希望对大家有所帮助!关于vuex就不再赘述,简单回顾一下:当应用碰到多个组件共享状态时,简单的单向数据流很容易被破坏:第一,多个视图依赖于同一...
    99+
    2023-05-14
    javascript vuex
  • 深入解析HetuEngine实现OnYarn原理
    目录什么是On Yarn?HetuEngine架构HetuEngine On Yarn原理依赖文件租户绑定资源管理客户端使用摘要:本文介绍HetuEngine实现On Yarn的原理...
    99+
    2024-04-02
  • Vue深入讲解数据响应式原理
    目录响应式是什么如何实现数据响应式实现对象属性拦截通用的劫持方案总结响应式是什么 简而言之就是数据变页面变 如何实现数据响应式 在Javascript里实现数据响应式一般有俩种方案,...
    99+
    2024-04-02
  • SpringBoot超详细深入讲解底层原理
    目录手写springbootSpringboot项目自动配置小结手写springboot 在日常开发中只需要引入下面的依赖就可以开发Servlet进行访问了。 <depende...
    99+
    2024-04-02
  • Vueslot插槽作用与原理深入讲解
    目录前言什么是Slot栗子在插槽中使用数据备胎插槽具名插槽覆盖问题作用域插槽具名插槽的作用域解构插槽Prop具名插槽的缩写$scopedSlots前言 在2.6.0中,具名插槽 和 ...
    99+
    2023-01-17
    Vue slot插槽作用 Vue slot插槽原理 Vue slot插槽
  • 深入理解Golang接口的实现原理
    深入理解Golang接口的实现原理,需要具体代码示例 Golang(又称Go语言)作为一种快速、可靠的编程语言,广受开发者青睐。其中,接口(Interface)是Golang语言中非常...
    99+
    2024-03-07
    原理 接口 golang go语言
  • 深入解析MySQL MVCC 原理与实现
    深入解析MySQL MVCC 原理与实现MySQL是目前最流行的关系型数据库管理系统之一,它提供了多版本并发控制(Multiversion Concurrency Control,MVCC)机制来支持高效并发处理。MVCC是一种在数据库中处...
    99+
    2023-10-22
    原理 MySQL mvcc
  • 深入详解Vue3ref底层实现原理
    目录前言源码解析实践操作class类的get和set是什么结论前言 随着现在vue3越来越普及,相应的面试题也多了起来 说到vue3的面试题,有一个最经典的就是ref和reactiv...
    99+
    2023-05-17
    Vue3 ref实现原理 Vue3 ref原理 Vue3 ref
  • SpringBoot中热部署配置深入讲解原理
    目录热部署springboot项目热部署实现原理在springboot中进行热部署操作步骤重启与重载自动启动热部署参与热部署监控的文件范围配置关闭热部署总结热部署   &n...
    99+
    2023-01-28
    SpringBoot热部署配置 SpringBoot热部署
  • require加载器实现原理的深入理解
    前言 我们常说node并不是一门新的编程语言,他只是javascript的运行时,运行时你可以简单地理解为运行javascript的环境。在大多数情况下我们会在浏览器中去运行java...
    99+
    2024-04-02
  • Java并发之synchronized实现原理深入理解
    目录synchronized的三种应用方式synchronized作用于实例方法synchronized作用于静态方法synchronized同步代码块synchronized底层语...
    99+
    2024-04-02
  • Java深入讲解AWT实现事件处理流程
    目录AWT的事件处理AWT中的事件继承图事件适配器小结AWT的事件处理 事件处理主要是为了响应用户的操作 事件对象(Event):封装了GUI组件上发生的特定事件(通常就是用户的一次...
    99+
    2024-04-02
  • Spring深入分析讲解BeanUtils的实现
    目录背景DOBODTOVO数据实体转换使用方式原理&源码分析属性赋值类型擦除总结背景 DO DO是Data Object的简写,叫做数据实体,既然是数据实体,那么也就是和存储...
    99+
    2024-04-02
  • HDFS原理深入理解
    1.HDFS概述   1)数据量越来越多,在一个操作系统管辖的范围存不下了,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,因此迫切需要一种系统来管理多台机器上的文件,这就       是分布式文件管理系统。 2)是一种允许...
    99+
    2017-01-26
    HDFS原理深入理解
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作