Skip to content

Commit 44aa90e

Browse files
committed
observer cleanup
1 parent 7a4de5f commit 44aa90e

File tree

2 files changed

+37
-17
lines changed

2 files changed

+37
-17
lines changed

src/directives/repeat.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
var Observer = require('../observer'),
2-
Emitter = require('../emitter'),
32
utils = require('../utils'),
43
config = require('../config'),
54
transition = require('../transition'),
@@ -136,7 +135,7 @@ module.exports = {
136135

137136
// listen for collection mutation events
138137
// the collection has been augmented during Binding.set()
139-
if (!collection.__observer__) Observer.watchArray(collection, null, new Emitter())
138+
if (!collection.__observer__) Observer.watchArray(collection)
140139
collection.__observer__.on('mutate', this.mutationListener)
141140

142141
// create child-vms and append to DOM
@@ -157,6 +156,7 @@ module.exports = {
157156
this.queued = true
158157
var self = this
159158
setTimeout(function () {
159+
if (!self.compiler) return
160160
self.compiler.parseDeps()
161161
self.queued = false
162162
}, 0)

src/observer.js

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ var ArrayProxy = Object.create(Array.prototype)
3232
methods.forEach(function (method) {
3333
def(ArrayProxy, method, function () {
3434
var result = Array.prototype[method].apply(this, arguments)
35-
this.__observer__.emit('mutate', this.__observer__.path, this, {
35+
this.__observer__.emit('mutate', null, this, {
3636
method: method,
3737
args: slice.call(arguments),
3838
result: result
@@ -109,13 +109,12 @@ function watchObject (obj) {
109109
* Watch an Array, overload mutation methods
110110
* and add augmentations by intercepting the prototype chain
111111
*/
112-
function watchArray (arr, path) {
112+
function watchArray (arr) {
113113
var observer = arr.__observer__
114114
if (!observer) {
115115
observer = new Emitter()
116116
def(arr, '__observer__', observer)
117117
}
118-
observer.path = path
119118
if (hasProto) {
120119
arr.__proto__ = ArrayProxy
121120
} else {
@@ -252,46 +251,61 @@ function ensurePath (obj, key) {
252251
* Observe an object with a given path,
253252
* and proxy get/set/mutate events to the provided observer.
254253
*/
255-
function observe (obj, rawPath, observer) {
254+
function observe (obj, rawPath, parentOb) {
255+
256256
if (!isWatchable(obj)) return
257+
257258
var path = rawPath ? rawPath + '.' : '',
258-
ob, alreadyConverted = !!obj.__observer__
259+
alreadyConverted = !!obj.__observer__,
260+
childOb
261+
259262
if (!alreadyConverted) {
260263
def(obj, '__observer__', new Emitter())
261264
}
262-
ob = obj.__observer__
263-
ob.values = ob.values || utils.hash()
264-
observer.proxies = observer.proxies || {}
265-
var proxies = observer.proxies[path] = {
265+
266+
childOb = obj.__observer__
267+
childOb.values = childOb.values || utils.hash()
268+
269+
// setup proxy listeners on the parent observer.
270+
// we need to keep reference to them so that they
271+
// can be removed when the object is un-observed.
272+
parentOb.proxies = parentOb.proxies || {}
273+
var proxies = parentOb.proxies[path] = {
266274
get: function (key) {
267-
observer.emit('get', path + key)
275+
parentOb.emit('get', path + key)
268276
},
269277
set: function (key, val, propagate) {
270-
observer.emit('set', path + key, val)
278+
parentOb.emit('set', path + key, val)
271279
// also notify observer that the object itself changed
272280
// but only do so when it's a immediate property. this
273281
// avoids duplicate event firing.
274282
if (rawPath && propagate) {
275-
observer.emit('set', rawPath, obj, true)
283+
parentOb.emit('set', rawPath, obj, true)
276284
}
277285
},
278286
mutate: function (key, val, mutation) {
279287
// if the Array is a root value
280288
// the key will be null
281289
var fixedPath = key ? path + key : rawPath
282-
observer.emit('mutate', fixedPath, val, mutation)
290+
parentOb.emit('mutate', fixedPath, val, mutation)
283291
// also emit set for Array's length when it mutates
284292
var m = mutation.method
285293
if (m !== 'sort' && m !== 'reverse') {
286-
observer.emit('set', fixedPath + '.length', val.length)
294+
parentOb.emit('set', fixedPath + '.length', val.length)
287295
}
288296
}
289297
}
290-
ob
298+
299+
// attach the listeners to the child observer.
300+
// now all the events will propagate upwards.
301+
childOb
291302
.on('get', proxies.get)
292303
.on('set', proxies.set)
293304
.on('mutate', proxies.mutate)
305+
294306
if (alreadyConverted) {
307+
// for objects that have already been converted,
308+
// emit set events for everything inside
295309
emitSet(obj)
296310
} else {
297311
var type = typeOf(obj)
@@ -307,14 +321,20 @@ function observe (obj, rawPath, observer) {
307321
* Cancel observation, turn off the listeners.
308322
*/
309323
function unobserve (obj, path, observer) {
324+
310325
if (!obj || !obj.__observer__) return
326+
311327
path = path ? path + '.' : ''
312328
var proxies = observer.proxies[path]
313329
if (!proxies) return
330+
331+
// turn off listeners
314332
obj.__observer__
315333
.off('get', proxies.get)
316334
.off('set', proxies.set)
317335
.off('mutate', proxies.mutate)
336+
337+
// remove reference
318338
observer.proxies[path] = null
319339
}
320340

0 commit comments

Comments
 (0)