During the interview, you will also be asked: Please explain the responsive principle of VUE2? , where there is elaboration or understanding, are generally known all words, know how much to say how much. Next, I will talk about their own understanding, remember not to recite, must understand, with their own language to describe it.

So what is reactive? Reactive is the function that runs when the object itself (adding or deleting values of the object) or the object properties (reassigning values) change, the most common of which is the render function.

In terms of implementation, VUE uses several core components, each of which solves a problem:

  1. Observer
  2. Dep
  3. Watcher
  4. Scheduler

🌟 Observer

The objective of the Observer is very simple: to convert an ordinary object into a responsive object.

To do this, the Observer converts each property of the Object through Object.defineProperty to a property with a getter and setter, so that when we access or set the property, the getter and setter methods are called, respectively. Vue has a chance to do something else.

An Observer is an internal vUE constructor that can be used indirectly through a static vUE method called vue.Observable (Object).

Example:

<body>
    <script src="./vue.min.js"></script>
    <script>
      let obj = {
        name:"Forensic".age:100.like: {a:"Harp".b:"Chess"
        },
        character: [{c:"Nice personality"}, {d:"How handsome!"
        }]
      }
      Vue.observable(obj);
    </script>
  </body>
Copy the code

Running results:

In the output… To indicate that the data is reactive, Invoke Property getter means that the getter method of the property is invoked. If there are still objects in the object, it will deeply recurse, making all the data responsive.

If in a component, the configured data also returns a response, this process occurs after beforeCreate and after created in the component lifecycle

In its concrete implementation, the Observer iterates recursively through all attributes of an object to complete data-responsive transformations. If an attribute was not originally present in the object and was added later, it will not be detected, so adding e:3 with obj. E = 3 will not be detected because it was not present in the object before. But with VUe3, using a proxy, you can detect it. So vue2 provides two instance methods, $set and $delete, which allow you to add or delete attributes to an existing reactive object.

Example:

Compare $set and $delete with delete and set by deleting nicknames and adding ages


<body>
    <div id="app">
      <p>Nickname: {{obj. Name}}</p>
      <p>Age: {{obj. Age}}</p>
         <! Delete obj. Name from obj.
      <button @click="delete obj.name">To delete a nickname</button>
      <button>Add the age</button>
    </div>

    <script src="./vue.min.js"></script>
    <script>
     let vm = new Vue({
        el:"#app".data(){
          return{
            obj: {name:"Forensic"}}}})</script>
  </body>
Copy the code

Running results:

From the running results, the name output by Vm. obj is responsive data before the delete nickname button is clicked. After the delete nickname button is clicked, print vm.obj again. At this time, the data has been deleted, but the nickname forensic is not deleted on the page. Because delete obj. Name is not detected

Next, use $delete to delete the nickname:

<body>
    <div id="app">
      <p>Nickname: {{obj. Name}}</p>
      <p>Age: {{obj. Age}}</p>
      <! -- use $delete to delete the nickname -->
      <button @click="$delete(obj,'name')">To delete a nickname</button>
      <button>Add the age</button>
    </div>

    <script src="./vue.min.js"></script>
    <script>
     let vm = new Vue({
        el:"#app".data(){
          return{
            obj: {name:"Forensic"}}}})</script>
  </body>
Copy the code

Running results:

When $delete is used, vue is notified of the nickname deletion and the page responds.

Similarly, let’s look at $set and set

 <body>
    <div id="app">
      <p>Nickname: {{obj. Name}}</p>
      <p>Age: {{obj. Age}}</p>
      <! -- -->
      <button @click="$delete(obj,'name')">To delete a nickname</button>
       <! Age =100 -->
      <button @click="obj.age=100">Add the age</button>
    </div>

    <script src="./vue.min.js"></script>
    <script>
     let vm = new Vue({
        el:"#app".data(){
          return{
            obj: {name:"Forensic"}}}})</script>
  </body>

Copy the code

Running results:

When you add attributes to an object using obj. Age =100, you can add attributes successfully, but the data is not responsive and the age is not displayed on the page.

Next, use $set to add attributes:

<body>
    <div id="app">
      <p>Nickname: {{obj. Name}}</p>
      <p>Age: {{obj. Age}}</p>
      <! Use $set to add age -->
      <button @click="$delete(obj,'name')">To delete a nickname</button>
      <button @click="$set(obj,'age','100')">Add the age</button>
    </div>

    <script src="./vue.min.js"></script>
    <script>
     let vm = new Vue({
        el:"#app".data(){
          return{
            obj: {name:"Forensic"}}}})</script>
  </body>
Copy the code

Running results:

At a glance, attributes added with $set are reactive, age:(…) Three points are obvious.

So that’s detection for objects, but what about arrays? How is an array checked? The change detection methods for Object and Array are different.

For an array, VUE changes its implicit stereotype because it needs to listen for methods that might change the contents of the array.

In short, the objective of the Observer is to have an object whose properties are read, assigned, and internal array changes detected by the VUE so that the data can be converted into responsive data.

🌼 Dep

There are two unanswered questions: what do YOU do when you read a property? What do YOU do when a property changes? This problem needs to be solved by Dep.

Dep stands for Dependency,

Vue creates a Dep instance for each property in the responsive object, the object itself, and the array itself. Each Dep instance has the ability to do two things:

  • Record dependencies: Who is using me
  • Send out updates: I have changed, and I want to inform those who use me

When a property of a reactive object is read, it does dependency collection: someone used me

When you change a property, it sends an update: Listen to those who use me, I’ve changed

🔥 Watcher

Now there’s another question, how does Dep know who’s using me?

To solve this problem, we need to rely on another thing, Watcher

When a function executes and uses reactive data, reactive data has no way of knowing which function is using it. Therefore, VUE solves this problem in a clever way:

Instead of executing the function directly, we hand it over to something called a Watcher, and a Watcher is an object, and every time a function like this is executed, it should create a Watcher and execute it through a Watcher. / / deP (deP); / / DeP (deP); / / DeP (deP); / / DeP (deP); / / DeP (deP); / / DeP (deP); / / DeP (deP); / / DeP (deP); / / DeP (deP); / / DeP (deP); / / DeP (deP); / / DeP (deP) There’s a Watcher that uses my property

When the Dep dispatches an update, it notifies all previously logged Watchers that I have changed

For each vUE component instance, there is at least one Watcher that records the render function of that component.

Watcher will first run the Render function once to collect dependencies, and the responsive data used in render will record the Watcher.

Dep notifying the Watcher when the data changes, and Watcher rerun the Render function to re-render the interface and re-record the current dependencies.

🌴 Scheduler

The last problem is that after the Dep informs Watcher, the response data changes several times, causing Watcher to run the corresponding function repeatedly, which may cause the function to run frequently, resulting in low efficiency

Imagine a function given to Watcher that uses attributes A, B, c, and D. The a, B, C, and D properties log dependencies, and the following code will trigger four updates:

state.a = "new data";
state.b = "new data";
state.c = "new data";
state.d = "new data";
Copy the code

So instead of immediately executing the render function, not just the render function, but any other function, watcher gets a notification to send out an update, it hands itself over to something called a scheduler, and inside the scheduler is a queue, which you can think of as an array, The scheduler maintains an execution queue. The same watcher only exists once in the queue. The watcher in the queue is not executed immediately, it is executed through a tool method called nextTick. Putting the watcher that needs to be executed into the microqueue of the event loop, nextTick is done through a Promise, and nextTick is essentially a function

nextTick((fn) = >{
    Promise.resolve().then(fn);// In this way, we run to the microqueue
})
Copy the code

That is, when reactive data changes, the render function executes asynchronously and in microqueues

👋 General flow chart

Let’s go over the flow chart briefly:

  1. The original object passesObserverWill be converted to a responsive object withgetterandsetterAnd then just wait.
  2. Then one day, during a thunderstorm, there’s a render function to execute, but instead of executing it directly, watcher executes it. Watcher reads the data by setting the global variable, and since it reads the data, it fires the getter for the responsive object. The getter then reads from the location of the global variable to the currently reading Watcher and collects the watcher into the Dep.
  3. The page will be rendered by the above steps.
  4. Another sudden day, beautiful day, I trigger a button or an event, whatever it is, the data changes, new steps —Distributed updateWatcher doesn’t execute it immediately because the data changes sometimes not one, but many, and the execution of many render functions or other data changes will be repeated, resulting in inefficient execution. Watcher, however, turns himself over to the schedulerScheduler
  5. The scheduler will add the Watcher to the queue, but will not execute it in the queuenextTickQueue, nextTick functions are all in the microqueue, and when the synchronous code is finished, it asynchronously executes functions fn1, fn2, Watcher, etc. This step is equivalent to re-executing watcher, then re-executing render function, and so on.

😛 ok, that’s all I have to share today. What questions can we have about the vuE2 responsive principle in the comments section

Be sure to like 👍 and support 😘