The whole process

As a front-end MVVM framework, the basic idea of Vue is the same as Angular and React. The core of Vue is that when data changes, the page DOM is refreshed automatically. This frees us from the tedious DOM manipulation and allows us to concentrate on business logic.

This is Vue’s two-way data binding (also known as the reactive principle). Two-way data binding is one of the most unique features of Vue. Here we use an official flow chart to briefly illustrate the entire flow of a Vue responsive system:

VueFor each component instancewatcherInstance object, which records properties as dependencies during component rendering and then as dependenciessetterIs notified when it is calledwatcherRecalculated so that its associated components can be updated.

"It's a classic observer model.Copy the code

The key role

In the implementation logic of Vue two-way data binding, there are three key roles:

  • Observer: It adds getters and setters to properties of an object for dependency collection and distribution of updates

  • Dep: Collects the dependencies of the current responsive objects. Each responsive object, including its children, has a Dep instance (where subs is an array of Watcher instances). When data changes, each Watcher is notified via dep.notify().

  • Watcher: an observer object. The instance can be divided into three types: render Watcher (render Watcher), computed attribute Watcher (computed Watcher), and listener Watcher (user Watcher)

Watcher’s relationship with Dep

Why is there a section devoted to this issue? Because most of you just know that the responsivity principle of Vue is implemented through Object.defineProperty. Objects bound by Object.defineProperty become “reactive”. That is, changing this object triggers get and set events.

However, the specific object dependencies are not very clear, which gives the interviewer the impression that you just memorized the answer, and that you are not very clear about the internal implementation details of responsiveness.

As for the relationship between Watcher and Dep, I was not very clear about it at the beginning. Only after consulting relevant materials did I gradually have a clear understanding of the specific implementation.

Just contactDepThis is a word that people are confused about:DepWhat is it for? We’re throughdefineReactiveMethod will bedataHow do we update the notification view even though we can listen for changes to the data in the response mode?

Dep is what helps us manage dependencies.

As shown in the figure above: an attribute may have multiple dependencies, and each reactive data has a Dep to manage its dependencies.

Summarize the rationale in one paragraph

Having said so much above, I summarize the core design ideas of Vue responsiveness:

When a Vue instance is created, the Vue iterates through the properties of the data option, hijacking the read of the data with object.defineProperty adding getters and setters for the property (getters for dependency collection, setters for issuing updates), and internally tracing dependencies before the property is accessed Ask and notify changes when revising.

Each component instance has a watcher instance that records all dependent data attributes (for dependency collection, computed Watcher,user) during component rendering Watcher instance), and then when the dependency is changed,setter methods notify the Watcher instance that depends on the data to recalculate (dispatch updates), thereby rerendering its associated component.

At this point, we have understood the “routine”, let’s use pseudo code to implement Vue responsiveness!

Function observe(target) {function observe(target) {// If target is an object, If (target && typeof Target === "Object") {object.keys (target).foreach ((key) => {// defineReactive assigns a "listener" to the target attribute  defineReactive(target, key, target[key]); }); Function defineReactive(target, key, val) {const dep = new dep (); // The attribute value can also be of object type, in which case you need to recursively traverse observe(val); DefineProperty (Target, key, {// Enumerable: true, // Can not configure different information: false, get: Disables any additional information. function () { return val; }, // Set: function (value) {dep.notify(); }}); } class Dep { constructor() { this.subs = []; } addSub(sub) { this.subs.push(sub); } notify() { this.subs.forEach((sub) => { sub.update(); }); }}Copy the code