The introduction

I believe that most of the front-end partners have lost track of how many projects they have done and how much code they have written. Everyone writes Vue code like a textbook:

Export default {data () {return {MSG: 'click me'}}, methods: {say () {this. MSG = 'well done'}}}Copy the code
New Vue({el: '#app', router: router, render: h => h(app)})Copy the code

Everything seemed so natural. However, in your busy schedule, have you ever wondered how a small Vue instance can build such a complex front-end project with so much energy? To find out how Vue works and what it does, follow me today.

Vue can run on multiple platforms such as browser, WEEX, etc. This paper only analyzes the main line execution process of VUE in the browser environment.

Initialize the

Let’s first look at the Vue constructor:

Function Vue (options) {if (process.env.node_env! == 'production' && ! (this instanceof Vue)) {warn('Vue is a constructor and should be called with the 'new' keyword') this._init(options) }Copy the code

As you can see from the constructor of Vue, when we execute new Vue(), only one _init method is executed. _init initializes the VUE based on the options passed in. Initialization of props, data, life cycle, event mechanism is done during this process.

In the case of data initialization, vUE defines data attributes to the Vue instance via Object.defineProperty. This explains why we can change the value of the data attribute in vue by assigning this. MSG.

The above manipulation of data is just the beginning. To enable so-called reactive or data-driven updates, Vue goes one step further by creating an Observer Object that binds to data and converts all properties in the data into getters/setters via Object.defineProperty. When a property in data is accessed in the Vue instance (triggering getters), the Observer collects that property as a dependency on the Watcher instance, and then when a property in data is changed in the Vue instance (triggering setters), The Observer tells watcher instances that rely on this property to rerender the page.

Note: Each Watcher corresponds to a VUE instance

Together, Vue can modify this. MSG to trigger automatic updates to the page.

Finally, a diagram on vUE’s official website is used to help you understand this process again:

The template parsing

From the above analysis, we already know that when the data changes, the page will be rerendered. Let’s take a look at how Vue renders.

First, VUE parses the HTML template we wrote into an AST description object, which is a tree structure linked by children and parent, and completely describes all the information of the HTML tag.

For example, you have the following HTML template:

<div id="app">
    <p>{{msg}}</p>
</div>
Copy the code

An AST object of the following form is eventually parsed:

{
   attrs: [{name: "id", value: ""app"", dynamic: undefined, start: 5, end: 13}],
   attrsList: [{name: "id", value: "app", start: 5, end: 13}],
   attrsMap: {id: "app"},
   children: [{
        attrsList: [],
        attrsMap: {},
        children: [],
        end: 33,
        parent: {type: 1, tag: "div", ...},
        plain: true,
        pre: undefined,
        rawAttrsMap:{},
        start: 19
        tag: "p",
        type: 1
   }],
   end: 263,
   parent: undefined,
   plain: false,
   rawAttrsMap:{id: {name: "id", value: "app", start: 5, end: 13}},
   start: 0
   tag: "div",
   type: 1
}
Copy the code

Vue then generates the render function from the AST object, whose function body is roughly as follows:

with(this){
    return _c('div', {attrs:{"id":"app"}}, [_c('p', [_v(_s(msg))])])
}
Copy the code

That is, our template will end up as a render function inside vue.

It is generally recommended that you use template, EL, etc., to specify templates. You can also customize custom compiler functions by using render, but vue will eventually parse into the render function.

After the first virtual to real

After we get the render function, the VUE does not render directly into a DOM tree, but first uses the render function to get a VNode. In fact, this step is necessary, as we all know that manipulating DOM nodes frequently and in large numbers can be very performance intensive. Vue can avoid unnecessary DOM manipulation by comparing vNodes before rendering. Here is the general structure of a VNode:

{tag: "div", children: [{tag: "p",...}], data: {attrs: {id: "app"} elm: DOM node (div#app), parent: undefined, context: Vue instance,... }Copy the code

Finally, vue performs real DOM node insertions, updates, and deletions based on the results of diff, and triggers vue instance lifecycle hook functions. After that, all vue has to do is watch the data change and decide whether to re-render the page.

conclusion

The above is the main process in the initial rendering process of Vue, which can be summarized as initialize the option Object, build a responsive system through Object.defineProperty, then parse the template into render function, and then use render function to generate VNode. Before rendering, Diff the vNode and render it as necessary.

This article does not go into the details of each implementation of the code, initialization, responsive implementation principles, template rendering, instruction parsing, VNode diff, etc., stay tuned.

Pay attention to our