vue源码剖析系列-compute完成机制

原本vue的相应式应当才是重中之重。然则网上的文章许多许多。在看computed的完成之前。一定照样要把vue的相应式怎样完成好好看一下。或者说二者根本就是一样的东西。这边引荐几篇文章关于vue的相应式。

vue相应式简朴完成

vue慕课相应式手记

照样看看官网关于相应式的诠释:
《vue源码剖析系列-compute完成机制》

总的来说。vue完成相应式的症结有三个:watcher,dep,observe;

  1. observe:遍历data中的属性。在get,set要领中设置中心数据挟制

  2. dep:每一个属性都有一个本身的dep(音讯定阅起)用于订制该属性上的一切视察者

  3. watcher:视察者,经由过程dep完成对相应属性的监听视察。视察获得效果后,主动触发本身的回调

能够去看看vue2.3的这三部份源码。中心照样有许多优美的设想。比方一个全局唯一的Dep.target,在任何时刻都是唯一的值。以确保一致时间只要一个视察者在定阅。再比方,watcher中也会存下相干的定阅器,完成去重和完成一致个视察者的分组(这里是完成computed的症结),再如。watcher中的id也会唯一。用于异步更新的时刻不同时动身雷同的定阅。细致看看会收成不小。改天我把一切的相应式的代码也整顿一下。
在理解了相应式的情况下。我们来看看computed的完成。最简朴的一个demo以下:


<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<div id="app">
  <div name="test">{{computeA}}</div>

</div>
</body>
<script src="vue.js"></script>
<script type="text/javascript">
  new Vue({
  el: '#app',
  data: function () {
    return {
      firstName: 111,
      lastName: 222
    }
  },
  computed: {
    computeA: function () {
      return this.firstName + ' ' + this.lastName
    }
  },
  created(){
    setTimeout(
      () => {
        this.firstName = 333;
      },1000
    )
  }
})
</script>
</html>

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

  1. 在初始化实例竖立相应式的时刻。对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的函数。觉得看的还不够细啊

    原文作者:fengruiabc
    原文地址: https://segmentfault.com/a/1190000009862528
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞