Vue update process nextTick is followed by an initialization process

preface

This article will focus on the asynchronous update strategy of VUE, including the virtual DOM and diff details (better to look at the source code flow) download the source code and configure the debugging tools were explained in the previous article

Previous link: juejin.cn/post/692310…

advice

This article may take about half an hour to read, and you can enjoy it with a cup of coffee and herbal tea, but I think it’s worth the time to make sense of it

Let’s start our operation

We’ll start today with core/observe/index.js

  • After this method turns the data into reactive

  • When data changes, dep.notify triggers the update process

Next, take a look at what happens inside the dep.notify method

  • Copy thesubsCopy (The subs array in which the arguments are executeddefineReactive getWhen willwatcherPut it in)
  • performupdateTo start the updatewatcherThe queue

The update method is located in core/observer/watcher.js

  • this.lazyThis is performed when the computed generated watcher property is computed
  • this.syncOperations that are performed only when the user actively sets the synchronization mode are not performed
  • We’ll focus on execution this timequeueWatcherThe process of asynchronous updating

Moving on to the queueWatcher internal process, the queueWatcher method is located at core/observe/schedular

  • First of all, you can see that has is de-evaluated based on the ID in watcher (has is an object).

  • Put watcher in queue for future updates

  • Further down we see nextTick. Note that nextTick is the same as this.$nextTick and vue.nexttick we used in the page

  • We can start by taking a look at the parameter flushSchedulerQueue currently passed by nexTIck in an asynchronous process, which is important for later understanding

FlushSchedulerQueue internal

  • And then we’re going to focus on thatrunMethod. So let’s look at this for nowThe point is to distinguishnextTickWhether you receive a method passed in from a component or a method passed in during an asynchronous update is important

Next, let’s look at the nextTick process

  • We can see what’s going to come in herecbMethods wrapped in a method push tocallbacksinternal
  • The current method is incompatible internally and will be executed in the futurecbmethods
  • And then it decidespendingIf we’re not in a pending state then we can start executingtimerFunc
  • timerFuncsIs a global variable

Now how does timerFuncs work

  • The internal preferred is to usepromise.thenDo it as a microtask
  • If the current environment does not supportpromiseThe case will continue down the useMutationObserverTo carry out
  • If none of the above methods are supported, it will be usedsetTimeoutThe way of

Then we look at the flushCallbacks method executed by timerFunc

  • Copy thecallbacksA copy of the
  • The method currently executed is what we have described above in the case of an asynchronous update processflushSchedulerQueue
  • Let’s move onflushSchedulerQueueThe inner run method, at this point, is going to be strung together with what we said above

Let’s look at the run method inside the flushSchedulerQueue

  • The main execution inside the method isgetmethods

Look inside the get method

  • Method internal executiongettermethods
  • getterApproach is towatcherThe second method passed in during instantiation is the update method for the current component
  • In summaryflushSchedulerQueueThe inside of therunMethod actually calls the update function of the current component
  • If you saw the last article you should know where this update function is instantiated and passed in, but it doesn’t matter if you didn’t let’s go back and see it again, okay

Is actually in the process of mount perform instantiation, mount process execution function $mount – > mountComponent position in core/instance/lifecycle. Js

  • Assigns the update method toupdateComponent
  • The update method executes internally_updateThe first argument received here is the component’s render function_renderThat is to say in the future_updateWhat the method receives internally is_renderThe value returned is the converted valuevdom
  • new WatcherWhen willupdateComponentPass it in. HereupdateComponentThat corresponds to what I said abovegetter

Let’s look inside the _render method, which is located in core/instance/render.js

  • We can see it directly_renderThe return value is onevnode
  • Line 82 is the transformationvnodeThe process of
  • render.callIt receives two arguments, the lastvm.$createElementIs ourrenderThe one in the methodH functionHow to convert a template syntax tree into a rendering function will be discussed in the next articlevnodeThe process of)

Next, we continue to see the internal _update method do what, position in the core/instance/lifecycle. Js

  • This is going to tell usprevVnodeIf there is proof it is the update process otherwise it is the initial conversation process
  • And we can see that they all call__patch__The difference is that the initialization process passes the first parameter to the host element, while the update process passes the previous vNode
  • So once you’ve done that, you’re done updating the page

Now let’s look at how the __Patch__ method is updated internally. It’s in core/vdom/patch.js and it’s around 700 lines. It’s a little bit long and it’ll be cut into two graphs


This time, we mainly look at the process of diff when updating, focusing on the patchVnode method. We need to know several DIFF update strategies of vue, which is important for us to understand the diff process

  • Comparing two VNodes, there are only three types of operations: attribute update, text update, and child node update

Conditions for updating two sets of nodes

  • The process of comparison is mainly through the way of two Pointers to the middle of the comparison

  • The head is compared with the head, the tail is compared with the tail, the head of the old node is compared with the tail of the new node, the tail of the old node is compared with the head of the new node, and the old node list is used to replace the position of the old node

  • If both the old and new nodes have children, perform the diff operation on the children and call updateChildren

  • If the new node has children and the old node does not, clear the text of the old node and add children to it

  • When a new node has no children and an old node has children, all children of the node are removed

  • When both old and new nodes have no children, only text replacement is performed

After that, we will continue to look at the interior of the patchVnode method. Here, the code of the update process will be posted and annotated. The code is a bit long and divided into two screenshots


And then we’re going to go to Update Hildren and this is the key and this is the diff process for the two sets of nodes, and we’re going to put all the comments in there to indicate that the code is a little bit long and there are two screenshots


Finally, let’s take a look at the detailed operation of the replacement process. What determines whether the current node can be reused or not

  • Here we can see the usekeyTo determine whether to continue the comparison
  • When you bind in the pagekeyThe subscript can only be seen on the page without error and without bindingkeyThe operation is the same
  • No binding by defaultundefinedIt’s going to keep going forward, and if it’s bound to subscripts then by default both sets of subscripts are the same and it’s going to go backwards like thatkeyIt doesn’t work so you try to keep it unique when you’re developing it uuid(If it is certain that the two sets of nodes will not be updated, the subscript can also be bound to the page without error)
  • There is somethingtagAnd so on will continue to judge

conclusion

Creation is not easy if you feel helpful might as well click a thumbs-up 😁

Happy New Year and good luck in everything