Does nextTick() work weirdly?

Can somebody explain the behavior of the code in the following fiddle?

JS Fiddle

I have always though, that nextTick() callback will be fired after next round of updates will be finished and the app will be fully synchronized with the state.
But we cant see value “B” in the DOM.

‘B’ do gets prints in nextTick you do not notice it because it is override by update value ‘C’ and those are in milliseconds. If you want to see your things work, do not use for loop for delay it take hardly takes 2 to 3 milliseconds use setTimeout to delay your call to assign the value ‘C’.

change: function () {
      this.value = 'B'
      Vue.nextTick(() => {
        console.log('Next Tick Called')
        setTimeout(() => this.value = 'C', 2000);
      });
    }

I know this is working, because this.value = "C" is 2 seconds postponed.

But I have really hard computations inside nextTick() callback and that is why I used for loop. What I need is to rerender view (value B has to be visible in the template) before my hard computations begin.

It is quite important question I think. UP.

Not sure if you are still searching, but the answer here on SO is decent.

As I understand it, the reason that B is never displayed in your fiddle is because nextTick() takes control of the DOM before rendering and makes sure that any operations inside the nextTick block are carried out before the re-render. So your this.value is overwritten with “C” before render.

Is there any reason for carrying out both the DOM update and the hard async calculations in the same function? If so, could a Promise be useful somehow maybe?

In this fiddle, you can see that the DOM was actually updated with “B” correctly, but the page wasn’t repainted yet:

https://jsfiddle.net/Linusborg/n9jmu5v7/24098/

this is because the the dom patching by Vue is done in a microtask on the same callstack, and the nexttick pushed another task on that microtask queue - which will also run before the browser can actually do a re-paint after the current callstack has finished.

Using setTimeout() with a couple ms delay on the other hand creates a macro task, pushing execution to the next callstack and gives the browser a brief window of time to do the repaint.

https://jsfiddle.net/Linusborg/n9jmu5v7/24101/ (using 60ms here)

setImmediate() has the same effect, but has to be polyfilled in IE if I recall correctly?

https://jsfiddle.net/Linusborg/n9jmu5v7/24103/

That’s as far as I myself understand it. the event loop & callstack are a fickle beast.

4 Likes

Nice examples and info - thanks!