2.6 Internal Change: Reverting
nextTick to Always Use Microtask
The Original Problem
When Vue detects data mutation, it asynchronously defer DOM updates to the next "tick" so that multiple mutations trigger only one update cycle. In versions before 2.5, Vue has been deferring updates using what is known as the "Microtask" (as explained in this blog post).
This works fine in most situations, but we discovered an edge case:
- Given two nested elements, "outer" and "inner";
- "inner" has a click event handler which triggers an update
- the update attaches another click event listener to "outer"
Step 3, when executed in a Microtask, happens before the click event bubbles up to "outer". As a result, the event listener on "outer" is triggered by the same event that caused it to be attached!
This is a very rare edge case, but it is very difficult for the user to figure out what is going on when they run into it.
The Use of Macrotask in 2.5
In 2.5.0, in order to work around this edge case, we changed the internal implementation of
nextTick to use Macrotasks instead of Microtasks when the update is triggered inside an event handler. However, the change has actually led to more problems of its own, outweighing the benefit of the fix.
Reverting to Microtask in 2.6 and Potential Side Effects
In 2.6, we managed to find a simpler fix for the edge case, which allowed us to revert
nextTick back to using Microtasks in all cases.
Since the new fix relies on checking DOM event timestamps to avoid unnecessary handler invocations, there is a very slight chance to cause some existing tests to fail: if a test creates a mock event before a test component is mounted, and uses that event to trigger handlers on the test component, it will not fire. This should be really rare in practice though (we found exactly one case in Vuetify's entire test suite).