资讯专栏INFORMATION COLUMN

vue源码解析系列-compute实现机制

Lsnsh / 1589人阅读

摘要:在看的实现之前。实现响应式的关键有三个遍历中的属性。在方法中设置核心数据劫持每个属性都有一个自己的消息订阅起用于订制该属性上的所有观察者观察者,通过实现对响应属性的监听观察。观察得到结果后,主动触发自己的回调可以去看看的这三部分源码。

本来vue的响应式应该才是重中之重。但是网上的文章很多很多。在看computed的实现之前。肯定还是要把vue的响应式如何实现好好看一下。或者说两者根本就是一样的东西。这边推荐几篇文章关于vue的响应式。

vue响应式简单实现

vue慕课响应式手记

还是看看官网对于响应式的解释:

总的来说。vue实现响应式的关键有三个:watcher,dep,observe;

observe:遍历data中的属性。在get,set方法中设置核心数据劫持

dep:每个属性都有一个自己的dep(消息订阅起)用于订制该属性上的所有观察者

watcher:观察者,通过dep实现对响应属性的监听观察。观察得到结果后,主动触发自己的回调

可以去看看vue2.3的这三部分源码。中间还是有很多精美的设计。比如一个全局唯一的Dep.target,在任何时候都是唯一的值。以确保同一时间只有一个观察者在订阅。再比如,watcher中也会存下相关的订阅器,实现去重和实现同一个观察者的分组(这里是实现computed的关键),再如。watcher中的id也会唯一。用于异步更新的时候不同时出发相同的订阅。仔细看看会收获不小。改天我把所有的响应式的代码也整理一下。
在理解了响应式的情况下。我们来看看computed的实现。最简单的一个demo如下:



    


{{computeA}}

我们来从源码的角度看看发生了什么:

在初始化实例创建响应式的时候。对options中的computed做了特殊处理:

function initComputed (vm, computed) {
  var watchers = vm._computedWatchers = Object.create(null);

  for (var key in computed) {
    var userDef = computed[key];
    var getter = typeof userDef === "function" ? userDef : userDef.get;
    {
      if (getter === undefined) {
        warn(
          ("No getter function has been defined for computed property "" + key + ""."),
          vm
        );
        getter = noop;
      }
    }
    // create internal watcher for the computed property.
    watchers[key] = new Watcher(vm, getter, noop, computedWatcherOptions);//为每一个computed项目订制一个watcher

    // component-defined computed properties are already defined on the
    // component prototype. We only need to define computed properties defined
    // at instantiation here.
    if (!(key in vm)) {
      defineComputed(vm, key, userDef);
    } else {
      if (key in vm.$data) {
        warn(("The computed property "" + key + "" is already defined in data."), vm);
      } else if (vm.$options.props && key in vm.$options.props) {
        warn(("The computed property "" + key + "" is already defined as a prop."), vm);
      }
    }
  

function defineComputed (target, key, userDef) {
  if (typeof userDef === "function") {
    sharedPropertyDefinition.get = createComputedGetter(key);
    sharedPropertyDefinition.set = noop;
  } else {
    sharedPropertyDefinition.get = userDef.get
      ? userDef.cache !== false
        ? createComputedGetter(key)
        : userDef.get
      : noop;
    sharedPropertyDefinition.set = userDef.set
      ? userDef.set
      : noop;
  }
  Object.defineProperty(target, key, sharedPropertyDefinition);
}

function createComputedGetter (key) {//构造该computed的get函数
  return function computedGetter () {
    var watcher = this._computedWatchers && this._computedWatchers[key];
    if (watcher) {
      if (watcher.dirty) {
        watcher.evaluate();//收集该watcher的订阅
      }
      if (Dep.target) {
        watcher.depend();//同一为这一组订阅再加上组件re-render的订阅(该订阅负责更新组件)
      }
      return watcher.value
    }
  }
}

总的来说。理解了响应式的构建之后。再来看computed的实现还是很直观的。组件初始化的时候。computed项和data中的分别建立响应式。data中的数据直接对属性的get,set做数据拦截。而computed则建立一个新的watcher,在组件渲染的时候。先touch一下这个computed的getter函数。将这个watcher订阅起来。这里相当于这个computed的watcher订阅了firstname和lastname。touch完后。Dep.target此时又变为之前那个用于更新组件的。再通过watcher.depend()将这个组统一加上这个订阅。这样一旦firstname和lastname变了。同时会触发两个订阅更新。其中一个便是更新组件。重新re-render的函数。感觉看的还不够细啊

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/83565.html

相关文章

  • Vuex源码解析

    摘要:可能会有理解存在偏差的地方,欢迎提指出,共同学习,共同进步。先来看一下这张的数据流程图,熟悉使用的同学应该已经有所了解。它允许用户在某些情况下避免自动安装。 写在前面 因为对Vue.js很感兴趣,而且平时工作的技术栈也是Vue.js,这几个月花了些时间研究学习了一下Vue.js源码,并做了总结与输出。 文章的原地址:https://github.com/answershuto/lear...

    chinafgj 评论0 收藏0
  • 从 VantComponent 谈 小程序维护

    摘要:不多废话,先说结论小程序组件写法这里就不再介绍。在官方文档中,我们可以看到使用构造器构造页面事实上,小程序的页面也可以视为自定义组件。经过一番测试,得出结果为为了简便。毕竟官方标准,不用担心其他一系列后续问题。 在开发小程序的时候,我们总是期望用以往的技术规范和语法特点来书写当前的小程序,所以才会有各色的小程序框架,例如 mpvue、taro 等这些编译型框架。当然这些框架本身对于新开...

    worldligang 评论0 收藏0
  • VUE - MVVM - part10 - Computed

    摘要:了解之后我们来实现它,同样的为了方便理解我写成了一个类这里的一般是的实例将属性代理到实例下的构造函数我们实现了代理属性和更新计算属性的值,同时依赖没变化时,也是不会触发的更新,解决了以上的个问题。 看这篇之前,如果没有看过之前的文章,移步拉到文章末尾查看之前的文章。 回顾 先捋一下,之前我们实现的 Vue 类,主要有一下的功能: 属性和方法的代理 proxy 监听属性 watche...

    callmewhy 评论0 收藏0
  • 深入解析Vue源码

    摘要:你可以使用的方法传入指令和定义对象来注册一个全局自定义指令。深度数据观察如果你希望在一个对象上使用自定义指令,并且当对象内部嵌套的属性发生变化时也能够触发指令的函数,那么你就要在指令的定义中传入。 Vue简介 数据绑定 /** *假设有这么两个钟东西 **/ //数据 var object = { message: Hello World! } //DOM {{ messag...

    weapon 评论0 收藏0
  • Vue源码解析(三)-computed计算属性&&lazy watcher

    摘要:前言源码解析一模版渲染源码解析二双向绑定官网给出的如下结果源码分析判断参数是否包含属性本例中本例中和是函数监听计算属性设置,延迟执行的方法设置可以通过本例方式访问计算属性对象初始化时会针对属性的所有值分别一个对象,在源码解析二中有详细介 前言 1、Vue源码解析(一)-模版渲染2、Vue源码解析(二)-MVVM双向绑定 demo 官网给出的demo如下 new Vue({ el...

    CoderStudy 评论0 收藏0

发表评论

0条评论

Lsnsh

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<