Skip to content

Commit 720ac15

Browse files
committed
fix batcher infinite update handling
1 parent 6c51c0a commit 720ac15

File tree

2 files changed

+31
-31
lines changed

2 files changed

+31
-31
lines changed

src/batcher.js

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ var config = require('./config')
1010
var queue = []
1111
var userQueue = []
1212
var has = {}
13+
var circular = {}
1314
var waiting = false
14-
var flushing = false
1515
var internalQueueDepleted = false
1616

1717
/**
@@ -22,15 +22,15 @@ function reset () {
2222
queue = []
2323
userQueue = []
2424
has = {}
25-
waiting = flushing = internalQueueDepleted = false
25+
circular = {}
26+
waiting = internalQueueDepleted = false
2627
}
2728

2829
/**
2930
* Flush both queues and run the jobs.
3031
*/
3132

3233
function flush () {
33-
flushing = true
3434
run(queue)
3535
internalQueueDepleted = true
3636
run(userQueue)
@@ -47,7 +47,20 @@ function run (queue) {
4747
// do not cache length because more jobs might be pushed
4848
// as we run existing jobs
4949
for (var i = 0; i < queue.length; i++) {
50-
queue[i].run()
50+
var job = queue[i]
51+
var id = job.id
52+
has[id] = null
53+
job.run()
54+
if (process.env.NODE_ENV !== 'production' && has[id] != null) {
55+
circular[id] = (circular[id] || 0) + 1
56+
if (circular[id] > config._maxUpdateCount) {
57+
queue.splice(has[id], 1)
58+
_.warn(
59+
'You may have an infinite update loop for watcher ' +
60+
'with expression: ' + job.expression
61+
)
62+
}
63+
}
5164
}
5265
}
5366

@@ -64,29 +77,14 @@ function run (queue) {
6477

6578
exports.push = function (job) {
6679
var id = job.id
67-
if (!id || !has[id] || flushing) {
68-
if (!has[id]) {
69-
has[id] = 1
70-
} else {
71-
has[id]++
72-
// detect possible infinite update loops
73-
if (has[id] > config._maxUpdateCount) {
74-
process.env.NODE_ENV !== 'production' && _.warn(
75-
'You may have an infinite update loop for the ' +
76-
'watcher with expression: "' + job.expression + '".'
77-
)
78-
return
79-
}
80-
}
81-
// A user watcher callback could trigger another
82-
// directive update during the flushing; at that time
83-
// the directive queue would already have been run, so
84-
// we call that update immediately as it is pushed.
85-
if (flushing && !job.user && internalQueueDepleted) {
80+
if (has[id] == null) {
81+
if (internalQueueDepleted && !job.user) {
8682
job.run()
8783
return
8884
}
89-
;(job.user ? userQueue : queue).push(job)
85+
var q = job.user ? userQueue : queue
86+
has[id] = q.length
87+
q.push(job)
9088
if (!waiting) {
9189
waiting = true
9290
_.nextTick(flush)

test/unit/specs/batcher_spec.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
var _ = require('../../../src/util')
2+
var config = require('../../../src/config')
23
var batcher = require('../../../src/batcher')
34
var nextTick = require('../../../src/util').nextTick
45

@@ -37,14 +38,15 @@ describe('Batcher', function () {
3738
})
3839

3940
it('allow diplicate when flushing', function (done) {
40-
batcher.push({
41+
var job = {
4142
id: 1,
43+
run: spy
44+
}
45+
batcher.push(job)
46+
batcher.push({
47+
id: 2,
4248
run: function () {
43-
spy()
44-
batcher.push({
45-
id: 1,
46-
run: spy
47-
})
49+
batcher.push(job)
4850
}
4951
})
5052
nextTick(function () {
@@ -93,7 +95,7 @@ describe('Batcher', function () {
9395
}
9496
batcher.push(job)
9597
nextTick(function () {
96-
expect(count).not.toBe(0)
98+
expect(count).toBe(config._maxUpdateCount + 1)
9799
expect(hasWarned(_, 'infinite update loop')).toBe(true)
98100
done()
99101
})

0 commit comments

Comments
 (0)