`watch(..., { flush: "pre" })` behaves like `"sync"`
Version
3.2.33
Reproduction link
Steps to reproduce
- (Just observe the output.)
What is expected?
Output:
pre, a: 2, b: 1
sync, a: 1, b: 0
sync, a: 2, b: 0
sync, a: 2, b: 1
post, a: 2, b: 1
What is actually happening?
Output (only difference is the pre
lines):
pre, a: 1, b: 0
pre, a: 2, b: 0
pre, a: 2, b: 1
sync, a: 1, b: 0
sync, a: 2, b: 0
sync, a: 2, b: 1
post, a: 2, b: 1
Unfortunately, the API docs on vuejs.org don't define the behavior of "pre"
, "sync"
and "post"
(also not here). Strangely, I found more exhaustive documentation here on w3cub.com (Vue 3-related), that says:
If
flush
is set to'sync'
, the callback will be called synchronously, as soon as the value changes.For both
'pre'
and'post'
, the callback is buffered using a queue. The callback will only be added to the queue once, even if the watched value changes multiple times. The interim values will be skipped and won't be passed to the callback.Buffering the callback not only improves performance but also helps to ensure data consistency. The watchers won't be triggered until the code performing the data updates has finished.
'sync'
watchers should be used sparingly, as they don't have these benefits.
- This exhaustive documentation should be on vuejs.org.
- Judging by what the option strings seem to represent and what makes sense, this description should be correct. But, in reality, Vue behaves like
"sync"
when"pre"
was passed and calls the callback immediately and synchronously, asconsole.log()
calls prove.
The output for "pre"
, as listed before, is expected to be diffrent to the current actual output for the following reasons:
- Triggering the watcher callback for each
a
mutation (a.value++
) should be reserved for"sync"
. - Triggering the watcher callback for each mutation of either
a
orb
is, in my opinion and according to my understanding, also in the realm of"sync"
. I'm trying to use"pre"
to watch multiple sources as a whole, sources that are often, but not always, mutated together and where a watcher-callback-run after the mutation of just one source might catch an inconsistent state, which leads to undefined behavior.- Perhaps the AND/OR behavior of
watch()
also isn't defined enough when there are multiple watch sources. Without knowing specifics about other use cases, it's conceivable that both logical linkings can be desirable. The default behavior should be clearly communicated and, if need be, an additional option should be added to get the other type of logical linking of the sources.
- Perhaps the AND/OR behavior of
This exhaustive documentation should be on vuejs.org.
Great Idea. Would be appreachiated if you were to make the docs team in the docs
repo aware by opening an issue there.
About the issue: Behavior not expected IMHO. Interestingly, this only seems to happen if the changes happen synchronously after the watcher has been defined. If you do these changes in onMounted()
, for example, you get the expected result.
This issue was raised a long time ago, only then was turned to are only discussed in the docs (https://github.com/vuejs/docs/issues/1154), but now since it has been solved, I thought of linking to leave a historical record.