|
|
@@ -8,13 +8,7 @@ import {
|
|
|
devtools
|
|
|
} from '../util/index'
|
|
|
|
|
|
-// We have two separate queues: one for internal component re-render updates
|
|
|
-// and one for user watcher registered via $watch(). We want to guarantee
|
|
|
-// re-render updates to be called before user watchers so that when user
|
|
|
-// watchers are triggered, the DOM would already be in updated state.
|
|
|
-
|
|
|
const queue: Array<Watcher> = []
|
|
|
-const userQueue: Array<Watcher> = []
|
|
|
let has: { [key: number]: ?true } = {}
|
|
|
let circular: { [key: number]: number } = {}
|
|
|
let waiting = false
|
|
|
@@ -26,7 +20,6 @@ let index = 0
|
|
|
*/
|
|
|
function resetSchedulerState () {
|
|
|
queue.length = 0
|
|
|
- userQueue.length = 0
|
|
|
has = {}
|
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
|
circular = {}
|
|
|
@@ -39,31 +32,17 @@ function resetSchedulerState () {
|
|
|
*/
|
|
|
function flushSchedulerQueue () {
|
|
|
flushing = true
|
|
|
- runSchedulerQueue(userQueue)
|
|
|
- runSchedulerQueue(queue.sort(queueSorter))
|
|
|
- // devtool hook
|
|
|
- /* istanbul ignore if */
|
|
|
- if (devtools && config.devtools) {
|
|
|
- devtools.emit('flush')
|
|
|
- }
|
|
|
- resetSchedulerState()
|
|
|
-}
|
|
|
|
|
|
-/**
|
|
|
- * Sort queue before flush.
|
|
|
- * This ensures components are updated from parent to child
|
|
|
- * so there will be no duplicate updates, e.g. a child was
|
|
|
- * pushed into the queue first and then its parent's props
|
|
|
- * changed.
|
|
|
- */
|
|
|
-function queueSorter (a: Watcher, b: Watcher) {
|
|
|
- return a.id - b.id
|
|
|
-}
|
|
|
+ // Sort queue before flush.
|
|
|
+ // This ensures that:
|
|
|
+ // 1. Components are updated from parent to child. (because parent is always
|
|
|
+ // created before the child)
|
|
|
+ // 2. A component's user watchers are run before its render watcher (because
|
|
|
+ // user watchers are created before the render watcher)
|
|
|
+ // 3. If a component is destroyed during a parent component's watcher run,
|
|
|
+ // its watchers can be skipped.
|
|
|
+ queue.sort((a, b) => a.id - b.id)
|
|
|
|
|
|
-/**
|
|
|
- * Run the watchers in a single queue.
|
|
|
- */
|
|
|
-function runSchedulerQueue (queue: Array<Watcher>) {
|
|
|
// do not cache length because more watchers might be pushed
|
|
|
// as we run existing watchers
|
|
|
for (index = 0; index < queue.length; index++) {
|
|
|
@@ -87,7 +66,14 @@ function runSchedulerQueue (queue: Array<Watcher>) {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- queue.length = 0
|
|
|
+
|
|
|
+ // devtool hook
|
|
|
+ /* istanbul ignore if */
|
|
|
+ if (devtools && config.devtools) {
|
|
|
+ devtools.emit('flush')
|
|
|
+ }
|
|
|
+
|
|
|
+ resetSchedulerState()
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -98,24 +84,17 @@ function runSchedulerQueue (queue: Array<Watcher>) {
|
|
|
export function queueWatcher (watcher: Watcher) {
|
|
|
const id = watcher.id
|
|
|
if (has[id] == null) {
|
|
|
- // if already flushing, and all user watchers have already been run,
|
|
|
- // run the new user watcher immediately.
|
|
|
- if (flushing && watcher.user && !userQueue.length) {
|
|
|
- return watcher.run()
|
|
|
- }
|
|
|
- // push watcher into appropriate queue
|
|
|
has[id] = true
|
|
|
- const q = watcher.user
|
|
|
- ? userQueue
|
|
|
- : queue
|
|
|
if (!flushing) {
|
|
|
- q.push(watcher)
|
|
|
+ queue.push(watcher)
|
|
|
} else {
|
|
|
- let i = q.length - 1
|
|
|
- while (i >= 0 && q[i].id > watcher.id) {
|
|
|
+ // if already flushing, splice the watcher based on its id
|
|
|
+ // if already past its id, it will be run next immediately.
|
|
|
+ let i = queue.length - 1
|
|
|
+ while (i >= 0 && queue[i].id > watcher.id) {
|
|
|
i--
|
|
|
}
|
|
|
- q.splice(Math.max(i, index) + 1, 0, watcher)
|
|
|
+ queue.splice(Math.max(i, index) + 1, 0, watcher)
|
|
|
}
|
|
|
// queue the flush
|
|
|
if (!waiting) {
|