In front of the stop

This article will not be introduced in detail Vue responsive principle, source code, because similar good articles nuggets a big push.

To understand the Vue responsive source code, it is recommended to see someone else’s detailed article, this article default you have mastered the principle of responsive, after all, I recorded it is also to deal with the interviewer. (the head)

Because every time an interviewer asks me about Vue responsiveness, I can’t organize my language well, so I just play a little bit ahead of time and write down what I think I need to answer.


The body of the

To explain the principle of responsiveness, we must first understand the role of the Observer Watcher Dep3 class in Vue source code, and their relationship.

If we make the relationship and connection of these three classes clear, then the general principle of the response form will be clear.

The Observer monitors and hijacks data in depth so that each value or set can be monitored and customized methods can be executed.

Wathcer, watch Is the data processed by the Observer, responsible for rendering and updating views. In reactive form it is a rendering Watcher.

Dep, which records the render Watcher and informs the render Wathcer to update the view. If not, Dep does not know who to notify when data changes.


Data Observer

Let’s start with a responsive entry, the Observer.

If you pass in data as an object, the Observer defineReactive each key value of your object. This is a deep recursion of data into getters and setters. The bottom layer is object.defineProperty

So what do we do in the getter and setter?

Getter

The Observer will give each property, new, a Dep instance to manage property dependencies. When you evaluate the data(Object), the Dep instance will remember the current render to Watcher.

Setter

When you set the value of the data(Object) and need to update the template, ask the watcher remembered before the deP notification to update it (dep.notify).

So far, we have roughly known the relationship between Observer, Dep and Watcher.

Attached is a stolen map.

The original link


In a nutshell, the Observer hijacks the data, Watcher updates the view, and Dep acts as a bridge between the Observer and Watcher, recording which Watcher updates the changes to the data.


With the above summary, continue to talk about the Observer.

We said above that if data is an Object, define active, using Object.defineProperty to hijack.

What if data is an array?

In fact, arrays are handled in reactive form by invoking another mechanism: overriding the Array prototype method.

Basically, when you call Array methods like push, you call your own push method and then execute the push method of the native Array.

The implementation details are:

1. Copy the array prototype first

let arrayMethods = Object.create(Array.prototype)
Copy the code

2. Then in the prototype object I created, I overwrite seven methods that change the array itself

// All seven methods can change the original array
let methods = [ 
    'push'.    'pop'.    'shift'. 'unshift'. 'sort'. 'reverse'. 'splice' ] methods.forEach(method= >{  arrayMethods[method] = function (. args) {  // Then when you invoke methods, observe the data observe   // Then call the native array method  Array.prototype[method].apply(this,args);  } }) Copy the code

3. Prototype chain that finally changes data

data.__proto__ = arrayMethods; 
Copy the code

So, when you execute data.push, you execute arrayMethods’ push first, and then arrayMethods’ arrayMethods’ push, after processing its logic, you call array. push to override the native Array.

Because of this mechanism, there is no need to iterate over each item of the array to observe, and because of this mechanism, there is no way to update the view by calling the index of the array directly, instead calling the set method.


Depends on the data scheduling center Dep

When we say Observer, we will call dep. Depend to collect the data and push the corresponding Watcher into the subs array.

With this array, if you’re setting a property, call dep.notify, which essentially updates every watcher in the subs.

    notify(){
        this.subs.forEach(watcher= >watcher.update())
    }
Copy the code

Dep and Watcher are many-to-many

Each property has a DEP property, which holds the Watcher.

— There can be more than one Watcher in a DEP, because a watcher can be dependent on multiple attributes


The subscriber Watcher

The subs array in the DEP contains the render Watcher, which is used to render and update the view.

When dep.notify is called, the update method is called on all watchers of this property.

The update method is used to update the view, and the nextTick optimization is used to save performance, which is a sort of anti-shake.

The whole process is basically:

After calling Update, optimize with nextTick. Then call the updated callback function.

This update callback generates the new render function, which generates the new Vnode, which generates the actual DOM rendering view.

This completes the process of data changes to template updates.

This article is formatted using MDNICE