Vue Dependency Collection Principle analysis

Source: Internet
Author: User

This article has been published by the author Wu Weiwei authorized NetEase Cloud community.

Welcome to NetEase Cloud Community, learn more about NetEase Technology product operation experience.



When the Vue instance is initialized, it can accept the following types of data:

    • Template

    • Initializing data

    • Property values passed to the component

    • Computed

    • Watch

    • Methods

Vue analyzes the data it relies on when it transforms data and templates into DOM nodes, based on data that is accepted at the time of instantiation. Automatically re-renders DOM nodes in the next cycle when specific data changes

This article mainly analyzes how Vue is dependent on collection.

In Vue, the classes related to dependency collection are:

DEP: A list class for Subscribers that can add or remove subscribers and can send messages to subscribers

Watcher: Subscriber class. It can accept getter at initialization, callback two functions as arguments. The getter is used to calculate the value of the Watcher object. When watcher is triggered, the value of the current watcher is recalculated through the getter, and callback is executed if the value changes.

Handling of initialized data

For a Vue component, a build function that initializes the data is required. As follows:

Export default {data () {return {text: ' Some texts ', arr: [], obj: {}}}}

Vue maintains a list of subscribers for each key in the data. For the generated data, each key is processed by Object.defineproperty, mainly by setting the get, set method for each key, which collects subscribers for the corresponding key and notifies the corresponding subscribers when the value changes. Some of the code is as follows:

  CONST DEP = NEW DEP ()   const property =  Object.getownpropertydescriptor (Obj, key)   if  (property &&  Property.configurable === false)  {    return  }  //  cater for pre-defined getter/setters  const getter = property  && property.get  const setter = property &&  Property.set  let childob = observe (val)   object.defineproperty (obj,  Key, {    enumerable: true,    configurable: true,     get: function reactiveGetter  ()  {       const value = getter ? getter.call (obj)  : val       if  (Dep.target)  {         dep.depend ()         if  (CHILDOB)  {          childob.dep.depend ()          }        if  (Array.isarray (value))  {          dependarray (value)          }      }      return  value    },    set: function reactivesetter  (NewVal)  {      const value = getter ? getter.call (obj)  : val      /* eslint-disable no-self-compare */       if  (newval === value | |   (NEWVAL !== NEWVAL && VALUE&Nbsp;! == value))  {        return       }      /* eslint-enable no-self-compare */       if  (process.env.node_env !==  ' production '  &&  Customsetter)  {        customsetter ()        }      if  (Setter)  {         setter.call (Obj, newval)       } else {         val = newVal      }       childob = observe (newval)       dep.notify ()     }  })

Each key has a list of subscribers const DEP = new DEP ()

When you assign a value to a key, if the value changes, all Subscribers are notified Dep.notify ()

When you take a value on a key, if Dep.target has a value, there are additional actions to add subscribers, in addition to the normal value-taking operation. Most of the time, the value of Dep.target is null, and only if the Subscriber is doing a subscription operation, Dep.target has a value for the subscriber who is subscribing. Taking a value operation at this point will add the Subscriber to the corresponding list of subscribers.

When subscribing to a subscription, the Subscriber consists of the following 3 steps:

    • Put yourself on the Dep.target

    • Value the key you rely on

    • Remove yourself from the Dep.target

After performing the subscription operation, subscribers are added to the list of subscribers to the relevant key.

Handling for objects and arrays

If the value assigned to the key is an object:

    • Each key in this object is recursively processed

If the value assigned to the key is an array:

    • Recursively handles each object in the array

    • Redefine the Push,pop,shift,unshift,splice,sort,reverse method of the array, and the subscriber list of key when calling the above method notifies subscribers that "value has changed". If the Push,unshift,splice method is called, the newly added item is recursively processed

Handling of templates

Vue processes the template into a render function. When the DOM needs to be re-rendered, the render function generates a virtual node in conjunction with the data in the Vue instance. The new virtual node is compared with the original virtual node to modify the DOM nodes that need to be modified.

Subscribed by

Subscribers mainly accept 2 parameter getter when initializing, callback. Getter is used to calculate the value of a subscriber, so it performs a value for all keys that subscribers need to subscribe to. Subscribers ' subscription operations are implemented primarily through getter.

Some of the code is as follows:

  /**   * Evaluate the getter, and re-collect  dependencies.   */  get  ()  {    pushtarget (this)      let value    const vm = this.vm     if  (This.user)  {      try {         value = this.getter.call (VM, VM)       }  catch  (e)  {        handleerror (e, vm,  ' getter  for watcher  "${this.expression}" ')       }     } else {      value = this.getter.call (VM, VM)     }    //  "Touch"  every property so they  are all tracked as    // dependencies for deep watching    if  ( This.deep)  {      traverse (value)     }     poptarget ()     this.cleanupdeps ()     return value   }

Main steps:

    • Put yourself on the Dep.target (Pushtarget (This))

    • Execute Getter (This.getter.call (VM, VM))

    • Remove yourself from Dep.target (Poptarget ())

    • Pre-cleanup subscriptions (this.cleanupdeps ())

Thereafter, the value of the dependent key will be notified when the Subscriber is changed. Subscribers who are notified will not be immediately triggered, but will be added to an array to be triggered and uniformly triggered in the next cycle.

When the subscriber is triggered, a getter is executed to calculate the subscriber's value, and if the value changes, the callback is executed.

subscribers who are responsible for rendering the DOM

When Vue is instantiated, it generates a subscriber to render the DOM. The Getter method that this subscriber passes in when instantiating is the method that renders the DOM.

Some of the code is as follows:

Updatecomponent = () = {vm._update (Vm._render (), hydrating)}vm._watcher = new Watcher (VM, Updatecomponent, NoOp)

Vm._render () combines templates and data to calculate virtual Dom Vm._update () renders real DOM nodes based on virtual DOM

This Subscriber initiates a subscription operation at the time of initialization. The getter passed in when instantiated is updatecomponent. The Vm._render () in which all dependent keys are evaluated at execution time will be able to complete the subscription to the dependent key. At the same time Vm._update () completed the first DOM rendering. The value of the currently dependent key is changed, and when the Subscriber is triggered, the updatecomponent as a getter is re-executed and the DOM is re-rendered. Since the value returned by the getter is always undefined, the callback in this Subscriber is not used, so an empty function noop is passed in as callback

The treatment of computed

By using computed, you can define a set of computed properties, which can be extracted by calculating the properties and keeping the template simple and clear.

code example:

Export default {data () {return {text: ' Some texts ', arr: [], obj: {} }}, computed: {key1:function () {return this.text + This.arr.length}}}

When defining a computed property, you need to define a key and a calculation method.

When Vue handles computed, it generates a lazy subscriber for each computed property. A normal subscriber performs a getter when instantiating and triggering to calculate its own values and perform subscription operations. In this case, the lazy subscriber will only put itself in the dirty state and not perform any other operations. When a subscriber executes its own evaluate method, it clears its own dirty state and executes a getter to calculate its own value and to subscribe.

The sample code for Vue when generating subscribers for computed properties is as follows:

Const Computedwatcheroptions = {Lazy:true}//create internal watcher for the computed property.watchers[key] = new WATC Her (VM, getter, NoOp, Computedwatcheroptions)

The incoming getter is a custom calculation method and callback is an empty function. (Lazy subscribers never have a chance to execute callback)

Vue defines the Get method for the specified key on its own instance so that the value of the computed property can be obtained from the Vue instance.

Some of the code is as follows:

function Createcomputedgetter (key) {return function Computedgetter () {Const Watcher = this._computedwatchers & & This._computedwatchers[key] if (watcher) {if (Watcher.dirty) {watcher.evaluate ()} if (De P.target) {watcher.depend ()} Return Watcher.value}}}

When a value is taken for a key that is defined by a computed property, the previously generated subscriber is first obtained. The value of the evaluate calculation Subscriber is executed only if the Subscriber is in the dirty state. Therefore, the calculation method defined for the computed attribute is executed only if the key of the computed property is evaluated and the key to which the property depends is changed.

If you value the computed attribute Key1 defined above

Vm.key1; The first time value, the custom calculation method executes the Vm.key1; The second value, the value of the dependent key does not change, the custom calculation method does not perform vm.text = '//change the value of the key that the computed property depends on, the subscriber of the calculated attribute will enter the dirty state, and the custom calculation method will not execute vm.key1; The third value, the value of the key to which the property is dependent is changed, and the computed attribute is evaluated, and the custom calculation method executes
Changes to the subscription computed property value

A key that calculates a property does not maintain a list of subscribers, nor does it trigger all subscribers by using the set method of the computed property. (Computed properties cannot be assigned). A subscriber performing a subscription operation to subscribe to a change in the value of a computed property is actually a change in the value of the key that subscribes to the computed property dependency. In the Get method of the computed property

if (dep.target) {watcher.depend ()}

If a subscriber subscribes to a change in the computed attribute, the computed property copies its own subscription to the Subscriber who is subscribing. This is how Watcher.depend () works.

For example:

Initialize subscriber watcher, dependent computed property Key1var watcher = new Watcher (function () {return vm.key1}, noop) Vm.text = "//computed property Key1 dependent text Watcher will be triggered when the value of the
The handling of Watch

When Vue is instantiated, it is possible to pass in the Watch object to listen for changes in some values. For example:

Export default {watch: {' A.B.C ': function (val, oldval) {Console.log (val) console.log (o Ldval)}}}

Vue generates a subscriber for each item in watch. The subscriber's getter is obtained by processing a string. such as ' A.B.C ' will be processed into

Function (VM) {var a = vm.a var B = a.b var c = B.C return C}

The source code for processing strings is as follows:

/** * Parse Simple path. */const Bailre =/[^\w.$]/export function Parsepath (path:string): any {if (bailre.test (path)) {return} const SE  gments = Path.split ('. ') return function (obj) {for (Let i = 0; i < segments.length; i++) {if (!obj) return obj = Obj[segments[i] ]} return obj}}

The subscriber's callback is the listener function that was passed in when the watch was defined. When a subscriber is triggered, callback is executed if the value of the Subscriber changes. Callback executes when the changed value is passed, the value before the change as the parameter.


NetEase Cloud Free Experience Pavilion, 0 cost experience 20+ Cloud products!

More NetEase technology, products, operating experience sharing please click.


Related articles:
"Recommended" frequently used data mining software/software package Large Inventory

Vue Dependency Collection Principle analysis

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.