NextTick source analysis

var callbacks = []; var pending = false; function nextTick(cb, ctx) { var _resolve; callbacks.push(function() { if (cb) { try { cb.call(ctx); } catch (e) { handleError(e, ctx, 'nextTick'); } } else if (_resolve) { _resolve(ctx); }}); if (! pending) { pending = true; timerFunc(); } if (! cb && typeof Promise ! == 'undefined') { return new Promise(function(resolve) { _resolve = resolve; }}})

You can see in the nextTick function that you pass in the cb parameter, wrap it up and push it into the Callbacks array. The pending variable is then used to ensure that timerFunc() is executed only once in an event loop. Finally, execute if (! cb && typeof Promise ! == ‘undefined’), if the parameter CB does not exist and the browser supports Promise, then a Promise class instantiation object is returned. NextTick ().then(() => {}). When _resolve executes, it executes in the logic of then. Take a look at the definition of the timerFunc function, starting with the creation of a timerFunc function that executes asynchronously using a Promise

var timerFunc;
if (typeof Promise !== 'undefined' && isNative(Promise)) {
    var p = Promise.resolve();
    timerFunc = function() {
        p.then(flushCallbacks);
        if (isIOS) {
            setTimeout(noop);
        }
    };
}

The TimerFunc function calls the FlushCallbacks function with various asynchronously executed methods. Take a look at the flushCallbacks function

var callbacks = []; var pending = false; function flushCallbacks() { pending = false; var copies = callbacks.slice(0); callbacks.length = 0; for (var i = 0; i < copies.length; i++) { copies[i](); }}

Execute pending = false so that the next event loop can call the timerFunc function in the nextTick function. Var copies = callbacks.slice(0); callbacks.length = 0; Copy the callbacks set to be executed asynchronously to constant copies and clear the callbacks. The traversal copies then perform each function. Going back to nextTick is to wrap the function passed through the cb parameter and push it into the Callbacks collection. Let’s see how it’s packed.

function() { if (cb) { try { cb.call(ctx); } catch (e) { handleError(e, ctx, 'nextTick'); } } else if (_resolve) { _resolve(ctx); }}

The logic is simple. If the parameter cb has a value. Cb.call (CTX) is executed in the try statement. The CTX is the parameter passed to the function. HandleError (e, CTX, ‘nextTick’) is executed if the execution fails. If the parameter cb has no value. Execute _resolve(CTX) because nextTick returns a Promise class instantiation object for which cb has no value, then execute _resolve(CTX) to execute the logic of then.

conclusion

Now the main line logic of nextTice is pretty clear. Define a variable callbacks, wrap the function passed in with a function that executes the passed function, handles the scenario where the execution fails and the parameter cb does not exist, and then adds it to the callbacks. Call the timerFunc function where you iterate over callbacks to execute each function because timerFunc is an asynchronous function and define a variable pending to ensure that the timerFunc function is called only once in an event loop. This enables the nextTice function to execute the incoming function asynchronously.

Update Lifecycle

BeforeUpdate: Called when data is updated, which occurs before virtual DOM renderings and patches. You can further change the state in this hook without triggering additional rerendering. Updated: Any changes to the component itself, props received from the parent component, or data received from the Vuex trigger a virtual DOM rerender (Don has already rendered) and patch. And then calls updated.

The sequence of the parent-child component Update lifecycle and NextTick execution

The father’s beforeUpdate-> child’s beforeUpdate-> child’s update-> father’s update-> nextTick callback

</template> <div> <space>{{MSG}}</space> <button @click="add"> </button> </div> </template> <script> import space from "./space" export default { components:{ space }, data(){ return { msg:1 } }, BeforeUpdate (){console.log(" parent beforeUpdate")}, updated(){console.log(" parent updated")}, methods:{add(){this.msg++; This. $nextTick (() = > {the console. The log (" next ")})}}} < / script > / / subcomponents < template > < div > < slot > < / slot > < / div > < / template > <script> export default {beforeUpdate(){console.log(" subbeforeUpdate ")}, updated(){console.log(" subupdated ")}, } </script> // print result father beforeUpdate child beforeUpdate child updated father updated next

BeforeUpdate,updated is also executed in the microtask, but the microtask it is in was created first and therefore executed first. If I did it like this, I would get a different result

The add () {enclosing $nextTick (() = > {the console. The log (" next ")}) / / next mission to create, so first to implement this. Msg++; } // Prints results next parent beforeUpdate child beforeUpdate child updated father updated