|
|
@@ -11,6 +11,24 @@ function Batcher () {
|
|
|
|
|
|
var p = Batcher.prototype
|
|
|
|
|
|
+/**
|
|
|
+ * Reset the batcher's state.
|
|
|
+ */
|
|
|
+
|
|
|
+p.reset = function () {
|
|
|
+ this.has = {}
|
|
|
+ // we have two separate queues: one for directive updates
|
|
|
+ // and one for user watcher registered via $watch().
|
|
|
+ // we want to guarantee directive updates to be called
|
|
|
+ // before user watchers so that when user watchers are
|
|
|
+ // triggered, the DOM would have already been in updated
|
|
|
+ // state.
|
|
|
+ this.queue = []
|
|
|
+ this.userQueue = []
|
|
|
+ this.waiting = false
|
|
|
+ this.flushing = false
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* Push a job into the job queue.
|
|
|
* Jobs with duplicate IDs will be skipped unless it's
|
|
|
@@ -24,7 +42,18 @@ var p = Batcher.prototype
|
|
|
|
|
|
p.push = function (job) {
|
|
|
if (!job.id || !this.has[job.id] || this.flushing) {
|
|
|
- this.queue.push(job)
|
|
|
+ // A user watcher callback could trigger another
|
|
|
+ // directive update during the flushing; at that time
|
|
|
+ // the directive queue would already have been run, so
|
|
|
+ // we call that update immediately as it is pushed.
|
|
|
+ if (this.flushing && !job.user) {
|
|
|
+ job.run()
|
|
|
+ return
|
|
|
+ }
|
|
|
+ var queue = job.user
|
|
|
+ ? this.userQueue
|
|
|
+ : this.queue
|
|
|
+ queue.push(job)
|
|
|
this.has[job.id] = job
|
|
|
if (!this.waiting) {
|
|
|
this.waiting = true
|
|
|
@@ -34,32 +63,31 @@ p.push = function (job) {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Flush the queue and run the jobs.
|
|
|
- * Will call a preFlush hook if has one.
|
|
|
+ * Flush both queues and run the jobs.
|
|
|
*/
|
|
|
|
|
|
p.flush = function () {
|
|
|
this.flushing = true
|
|
|
- // do not cache length because more jobs might be pushed
|
|
|
- // as we run existing jobs
|
|
|
- for (var i = 0; i < this.queue.length; i++) {
|
|
|
- var job = this.queue[i]
|
|
|
- if (!job.cancelled) {
|
|
|
- job.run()
|
|
|
- }
|
|
|
- }
|
|
|
+ this.run(this.queue)
|
|
|
+ this.run(this.userQueue)
|
|
|
this.reset()
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Reset the batcher's state.
|
|
|
+ * Run the jobs in a single queue.
|
|
|
+ *
|
|
|
+ * @param {Array} queue
|
|
|
*/
|
|
|
|
|
|
-p.reset = function () {
|
|
|
- this.has = {}
|
|
|
- this.queue = []
|
|
|
- this.waiting = false
|
|
|
- this.flushing = false
|
|
|
+p.run = function (queue) {
|
|
|
+ // do not cache length because more jobs might be pushed
|
|
|
+ // as we run existing jobs
|
|
|
+ for (var i = 0; i < queue.length; i++) {
|
|
|
+ var job = queue[i]
|
|
|
+ if (!job.cancelled) {
|
|
|
+ job.run()
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
module.exports = Batcher
|