Small meatballs to see how the Vue response type

Source: Internet
Author: User
small meatballs To see how the Vue response type

After a few months with the big guys in the Vue project, the Vue is starting from 0.

Compared with the previously used regular and angular of the response of the dirty check mechanism, found that the Vue response is hit-type. When using angular or regular, the discovery updates a value, the framework checks for a number of unrelated values, picks out which data is dirty, can update the view, and so on. In the case of Vue computed, it is found that Vue will only examine the corresponding methods of the changed data, and other unrelated data-related methods will not be disturbed.

This article also takes the Vue computed computation attribute realization example, the Revelation Vue response realization. Directory

Look at the Vue. How to respond to a list of chestnuts principle Analysis 1 mixin 2 INITDATAVM 3 DEP message subscriber 4 Thiswatch Summary

1. Give me a chestnut.

When using Vue, computed is often used to dynamically get the value of the property.

Give me a chestnut:

<div id= "Example" >
  <input v-model= "Message1"/> <input v-model=
  "Message2"/>
  <p >computed reversed Message: "{{reversedmessage}}" </p>
</div>
var vm = new Vue ({
  el: ' #example ',
  data: {
    message1: ' Hello ',
    message2: ' World '
  },
  computed: { c6/>//The Getter
    reversedmessage:function () {//' this ' of the computed property points to the
      VM instance
      console.log (' modified ');
      Return This.message1.split ("). Reverse (). Join (")}}
    "

The above code displays two input boxes on the page, one line showing the text.

Left input box Two-way binding this.message1 variable, right input box two-way binding this.message2 variable, The bottom of the display box is bound this.reversedmessage variable, and is obtained by the computed property, defined as This.message1.split ("). Reverse (). Join (') The flip of the input box string on the left.

Run found the left of the input box changes, the following display text immediately get a response, update the current left input box text Flip, and the console print out changed. No matter how the input box on the right changes, the following display box and console are unchanged.

We found that Vue's computational attributes automatically distinguish who is changing to update dependent values. When this property changes, the function can sniff the change and automatically rerun it. 2. Principle Analysis

We know that the response principle of Vue is to use the getter and setter methods in the Object.defineproperty to collect the dependency in the getter method and respond to the notification in the setter method.

We boldly speculate that the author, in the design of computed, when a property definition is computed, a responsive dependency is associated between the data b of the computed property and the dependent data A, implementing a computed method that relies on A's data b in response to notification when the setter of dependency a is triggered.

Below through the source to uncover it ~

2.1 mixin

Vue properties, injected through mixin

//  ... 
Initmixin (Vue)   
statemixin (Vue)   //Injection Watcher Eventmixin
(Vue)
lifecyclemixin (Vue)
rendermixin (Vue)
// ...

Suppose that the official chestnuts:

var watchexamplevm = new Vue ({
  el: ' #watch-example ',
  data: {
    question: ',
    answer: ' I cannot give you n answer until ask a question! '
  },
  Watch: {
    //If ' question ' changes, this function will run
    question:function (new Question, oldquestion) {
      this.answer = ' Waiting for your to stop typing ... '
      this.getanswer ()
    }
  }
 });

After the Vue is injected into the watcher, it can have watch function when the VM. $options Watch method call.

After Vue has injected Init, Vue has the init feature. BlaBla 2.2 initdata (VM)

Now Vue has the init feature.

In the official Vue lifecycle diagram, the new Vue () is followed by the observe data process, so let's take a look at what this phase does.

Hand painting InitData Process diagram

First, Vue transfers vm. $options. Data to the VM.
Then, the data and its attributes are transformed in a responsive style.
The source code is as follows:

Vue.prototype._initdata = function () {this. $options =options;
    The data under the options is transferred to the VM under let data = This._data=this. $options. Data;
    Iterate through all of the data and add a response-type Object.keys (data). ForEach (Key=>this._proxy (key));
  Iterate through all of the data and its properties and add a response-type observe (data,this);
    }//Vue's response principle, not to mention vue.prototype._proxy = function (key) {var self = this;
        Object.defineproperty (self, key, {configurable:true, enumerable:true, Get:function Proxygetter () {
      return Self._data[key];
      }, Set:function Proxysetter (val) {Self._data[key] = val;  }}}//Traverse all data and its properties, add response export function observe (value, VM) {if (!value | | | typeof value!== ' object ') { Return 
  var ob;
  if (Hasown (value, ' __ob__ ') && value.__ob__ instanceof Observer) {ob = value.__ob__; else if (Shouldconvert && IsArray (value) | | isplainobject (value)) && object.isextensible (value) &am p;&!value._isvue){ob = new Observer (value);
  Ensure that each property has a __ob__ attribute, it is a Objserver object, which is the response of this thing added} if (ob && vm) {OB.ADDVM (VM);
return OB;
 }

Look at the implementation of the Observer class

Export default class  observer{
  Constructor (value) {
    this.value = value
    this.walk (value)
  }
  / /recursive ... Allow each property to be observe
  Walk (value) {
    Object.keys (value). ForEach (Key=>this.convert (Key,value[key))
  }
  convert (Key, Val) {
    definereactive (This.value, Key, Val)
  }
}

// This function does not understand dep.target it doesn't matter, after saying, first know is to create the response
export function definereactive (obj, key, Val) {
  var dep = new DEP ()
  var Childob = Observe (val)

  object.defineproperty (obj, key, {
    enumerable:true,
    configurable:true, Get
    : () =>{
      if (dep.target) {
        dep.addsub (dep.target)
      } return
      val
    },
    set: newval=> {
      var value =  val
      if (newval = = value) {return
      }
      val = newval
      Childob = Observe (newval)
      dep.notify ()
    }
  )
}


Export function observe (value, VM) {
  if (!value | | typeof value!== ' object ') {
    return
  } return
  new Observer (value)
}

To put it bluntly, adding a observer instance to each attribute is designed to implement adding getter and setter to each property to guarantee a response. 2.3 DEP: Message subscriber

Have you ever personally practiced JavaScript's message Notification subscription design pattern? DEP is designed to be a message subscriber.

Export Default class Dep {
  constructor () {
    this.subs = []
  }
  //Event Subscription
  Addsub (sub) {
    This.subs.push (sub)
  }
  //Event notification
  notify () {
    This.subs.forEach (sub=>sub.update ())
  }
}

A simple event notification subscription model.

Before you look at the Definereactive function:

This function does not understand dep.target it's okay, or it's back.
export function definereactive (obj, key, Val) {
  var dep = new dep ()
  var childob = Observe (val)

  object.defineproperty (obj, key, {
    enumerable:true,
    configurable:true, get
    : () =>{
      if (dep.target) {
        dep.addsub (dep.target)   //Subscription
      } return
      val
    },
    set:newval=> {
      var value =  val
      if (newval = = value) {return
      }
      val = newval
      Childob = Observe ( newval)
      dep.notify ()   //Publish
    }
  }

The hand drew a picture:

Each data and its attributes have a observer that gives the data response, which relies on the global DEP message Subscriber, the getter to subscribe to the message, the instance queue is stored by the DEP instance, the setter is the time to trigger the message, the watcher instance in the queue is notified, Run the event that the user wants.

Now that the Observer property of each data and its properties is implemented successfully and the instance of DEP is subscribed to, then watcher joins the DEP instance queue specifically. 2.4 this. $watch

Hand painting this. $watch process diagram (including the InitData process in the previous section)

Implementation of the Wacher class:

Export default class Watcher {
  constructor (VM, EXPORFN, CB) {
    THIS.CB = cb
    THIS.VM = VM
    THIS.EXPORFN = exp ORFN
    //2. The key place is here, the Data/property get method
    This.value = This.get ()
  }
  Update () {
    this.run () is called here.
  }
  Run () {
    const  value = This.get ()
    if (value!==this.value) {
      this.value = value
      this.cb.call ( THIS.VM)
    }
  get
  () {
    //1. The point is: put the global variable dep.target just want the current watcher instance
    Dep.target = this
    const Value = This.vm._data[this.exporfn]
    dep.target = null return
    value
  }
}

In fact, what watcher did.

The first step: Dep.target = This, for the second step, to execute the data get method, tell data, is Watcher trigger get method, not others oh.
Step Two: This.value = This.get (), a GET method that triggers data.

What does the Get method of data do? The code has been posted before.

Review:

Get: () =>{
      if (dep.target) {
        dep.addsub (dep.target)
      } return
      val
    }

The Get method determines that the Dep.target has a value (that is, a watcher trigger) and relies on the collection. Add the current break-in watcher to the dependency queue for your own DEP instance.

This implements the Vue response process. Concatenate the following figure three.

3. Summary

End.

Reference:
https://segmentfault.com/a/1190000010408657
https://www.imooc.com/article/14466

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.