Writing in the front

If your resume says “proficient in using Vue and have read some of its source code”, you will probably be asked this question.

What? If your resume doesn’t say you’ve read source code, chances are the interviewer will ask if you’ve read responsive source code

It’s the same song:

Earn not to escape but the brows can not be solved knot knot can not be solvedCopy the code

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 theVueTwo-way data binding (also known as the reactive principle). Data bidirectional binding isVueOne of the most unique features. Here we use an official flow chart to briefly illustrateVueThe whole process of a responsive system:

In Vue, each component instance has a corresponding Watcher instance object, which records properties as dependencies during component rendering and then, when setters for dependencies are called, informs Watcher to recalculate, causing its associated components to be updated.

This is a typical observer pattern.

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.

For those of you who are new to the word Dep, what is Dep for? After we respond to the data in the data via defineReactive method, how do we handle notification view updates even though we can listen for changes to the data?

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!

The core to realize

/ * * *@name Vue two-way data binding (responsive system) implementation principle */

// The observe method traverses and wraps object properties
function observe(target) {
  // If target is an object, iterate over it
  if (target && typeof target === "Object") {
    Object.keys(target).forEach((key) = > {
      // The defineReactive method puts a "listener" on the target attributedefineReactive(target, key, target[key]); }); }}// Define defineReactive method
function defineReactive(target, key, val) {
  const dep = new Dep();
  // The property value may also be of type object, in which case you need to call observe for recursive traversal
  observe(val);
  // Install a listener for the current property
  Object.defineProperty(target, key, {
    / / can be enumerated
    enumerable: true.// Cannot be configured
    configurable: false.get: function () {
      return val;
    },
    // The listener function
    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