Writing an article is not easy, click a like brother focus on Vue source code sharing, the article is divided into vernacular version and source version, vernacular version to help understand the working principle, source version to help understand internal details, let us study together based on Vue version [2.5.17]

If you think the layout is ugly, please click the link below or pull to the following public account can also be

Vue principle dependency collection – source code version of the basic data type

For those of you who have no concept of dependency collection, you can read this article first

[Vue principle] Responsive principle – vernacular version

The main purpose of dependency collection is to solve a problem. What problem?

First of all, we all know that Vue data is updated in response, and when data changes, so does where it is used.

So the question is, how does Vue know when the data changes, and how does it change where it’s being used?

That’s the problem dependency collection solves!

How did he solve it? Simply said is to rely on the data of the place, to the centralized collection in order to change the notification! Today we look at the source code process

First, reactive update is divided into two steps, dependency collection and dependency update

Today is about dependency collection, how do you collect where the data is being used

Dependency collection, in turn, is divided into two processes

1. Data initialization process

2. Rely on the collection process

In this article, I will take basic data types as an example. Because basic data and reference data are very different in processing, reference types need to understand more and more complex things, so we need to step by step, divided into two chapters


Data initialization process

First, when the instance is initialized, the data needs to be processed responsively, that is, object.defineProperty is used for each attribute

What is the process?

1. During instance initialization, initState is called to process some option data. InitData is used to process option data

Vue.prototype._init=function(){
    ...
    initState(this)
    ...

}

function initState(vm) {    

    var opts = vm.$options; . Options for props, computed, and watchif(opts.data) { initData(vm); }};Copy the code

2. InitData iterates through data, and definedReactive handles each attribute

function initData(vm) {  

    var data = vm.$options.data;

    data = typeof data === 'function'? data.call(vm, vm) : data || {}; / /... Traversal data data object key, duplicate name detection, compliance detection code New Observer(data); }functionObserver(value) { var keys = Object.keys(value); / /... Omitted codefor(var i = 0; i < keys.length; i++) { defineReactive(obj, keys[i]); }};Copy the code

DefinedReactive Assigns attributes to objects to be reactive via Object.defineProperty

functionDefineReactive (obj, key) {var dep = new dep (); var val = obj[key] Object.defineProperty(obj, key, { enumerable:true,        
        configurable: true.get() {... Depending on the collection, the detailed source code is released in the next process},set() {... Rely on update, source code next article released}}); }Copy the code

Dependency Collection process

Write a small example to explain

new Vue({    
    el: document.getElementsByTagName("div") [0],data() {return  {            
            name:11
        }
    }
})
Copy the code

The page template

The page references the data name. The name needs to save the watcher of the page, so that when the name changes, the page Watcher is notified to update

1. Page rendering functions

with(this){  
    return _c('div',{},[name])
}
Copy the code

2. Read name

The render function executes, the context object is bound to the instance, and name reads the name on the instance

3. Save Watcher

Name is read, natural go to the Object. The defineProperty. The get method, start from here to collect watcher

Take a look at the source code for the get omitted from defineReactive

function defineReactive(obj, key) {    

    var dep = new Dep();    
    var val  = obj[key]    

    Object.defineProperty(obj, key, {

        get() {            
            if(dep.target) {// Collect dependencies dep.addSub(dep.target)}return val
        }
    });
}
Copy the code

Hahaha, here’s where it gets interesting. This code is the core of dependency collection, with three main points

Dep.target Dep dep.addSub

1, Dep. Target

Dep.target points to various watcher, watcher for a watch, watcher for a page, and so on

Dep.target is variable, pointing to a different watcher depending on the current parsing process.

Dep.target = Specific watcherCopy the code

“Of course it’s not that simple. It just means something.”

So let’s just say, which watcher is pointing to, that watcher is using data, and data is collecting data from that watcher

You can forget about dep. target and just remember that in Watcher, right

For example, dep. target points to the watcher of the current page in advance when the current page starts rendering.

After the page rendering function executes and references the data name, the name directly collects dep. target, which will collect the watcher of the current page

Watcher has the ability to update instances, so they are collected, notified when data changes, and then called to update them

Watcher only plays the role of being collected in dependent collection, so I won’t explain it in detail here

2, Dep

Dep is a constructor that creates instances and has many methods

The instance will contain an array of properties subs for storing different data.

Look at the constructor of deP

var Dep = function Dep() {// Save watcher's array this.subs = []; };Copy the code

3, dep. AddSub

The prototype method adds watcher directly to dep.subs storage

Dep.prototype.addSub = function(sub) {    
    this.subs.push(sub);
};
Copy the code

So dep.addSub(dep.target) will add the current watcher directly

So the collection process goes something like this

1, page rendering function is executed, name is read

2, triggering the name of the Object. DefineProperty. The get method

The page’s watcher is then collected into the subs of the name – specific closure DEP


conclusion

Why rely on collection, as I’ve said before, in order to notify those who have used the data of changes

It’s like, you go to the store to buy something, it’s not available yet, so you give your phone number to the boss, and the boss puts yours in the phone book. When the item is available, you will be notified by phone and asked to pick it up (complete update).

Some of the steps involved are transformed by the example above

1. When you buy something, you use the data name

2. You give your boss your phone, which is your Watcher for notifications

3. The boss saved the watcher in the phone book.

4. The remaining steps are dependent updates