Skip to content

Commit

Permalink
observer cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Feb 13, 2014
1 parent 7a4de5f commit 44aa90e
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 17 deletions.
4 changes: 2 additions & 2 deletions src/directives/repeat.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
var Observer = require('../observer'),
Emitter = require('../emitter'),
utils = require('../utils'),
config = require('../config'),
transition = require('../transition'),
Expand Down Expand Up @@ -136,7 +135,7 @@ module.exports = {

// listen for collection mutation events
// the collection has been augmented during Binding.set()
if (!collection.__observer__) Observer.watchArray(collection, null, new Emitter())
if (!collection.__observer__) Observer.watchArray(collection)
collection.__observer__.on('mutate', this.mutationListener)

// create child-vms and append to DOM
Expand All @@ -157,6 +156,7 @@ module.exports = {
this.queued = true
var self = this
setTimeout(function () {
if (!self.compiler) return
self.compiler.parseDeps()
self.queued = false
}, 0)
Expand Down
50 changes: 35 additions & 15 deletions src/observer.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ var ArrayProxy = Object.create(Array.prototype)
methods.forEach(function (method) {
def(ArrayProxy, method, function () {
var result = Array.prototype[method].apply(this, arguments)
this.__observer__.emit('mutate', this.__observer__.path, this, {
this.__observer__.emit('mutate', null, this, {
method: method,
args: slice.call(arguments),
result: result
Expand Down Expand Up @@ -109,13 +109,12 @@ function watchObject (obj) {
* Watch an Array, overload mutation methods
* and add augmentations by intercepting the prototype chain
*/
function watchArray (arr, path) {
function watchArray (arr) {
var observer = arr.__observer__
if (!observer) {
observer = new Emitter()
def(arr, '__observer__', observer)
}
observer.path = path
if (hasProto) {
arr.__proto__ = ArrayProxy
} else {
Expand Down Expand Up @@ -252,46 +251,61 @@ function ensurePath (obj, key) {
* Observe an object with a given path,
* and proxy get/set/mutate events to the provided observer.
*/
function observe (obj, rawPath, observer) {
function observe (obj, rawPath, parentOb) {

if (!isWatchable(obj)) return

var path = rawPath ? rawPath + '.' : '',
ob, alreadyConverted = !!obj.__observer__
alreadyConverted = !!obj.__observer__,
childOb

if (!alreadyConverted) {
def(obj, '__observer__', new Emitter())
}
ob = obj.__observer__
ob.values = ob.values || utils.hash()
observer.proxies = observer.proxies || {}
var proxies = observer.proxies[path] = {

childOb = obj.__observer__
childOb.values = childOb.values || utils.hash()

// setup proxy listeners on the parent observer.
// we need to keep reference to them so that they
// can be removed when the object is un-observed.
parentOb.proxies = parentOb.proxies || {}
var proxies = parentOb.proxies[path] = {
get: function (key) {
observer.emit('get', path + key)
parentOb.emit('get', path + key)
},
set: function (key, val, propagate) {
observer.emit('set', path + key, val)
parentOb.emit('set', path + key, val)
// also notify observer that the object itself changed
// but only do so when it's a immediate property. this
// avoids duplicate event firing.
if (rawPath && propagate) {
observer.emit('set', rawPath, obj, true)
parentOb.emit('set', rawPath, obj, true)
}
},
mutate: function (key, val, mutation) {
// if the Array is a root value
// the key will be null
var fixedPath = key ? path + key : rawPath
observer.emit('mutate', fixedPath, val, mutation)
parentOb.emit('mutate', fixedPath, val, mutation)
// also emit set for Array's length when it mutates
var m = mutation.method
if (m !== 'sort' && m !== 'reverse') {
observer.emit('set', fixedPath + '.length', val.length)
parentOb.emit('set', fixedPath + '.length', val.length)
}
}
}
ob

// attach the listeners to the child observer.
// now all the events will propagate upwards.
childOb
.on('get', proxies.get)
.on('set', proxies.set)
.on('mutate', proxies.mutate)

if (alreadyConverted) {
// for objects that have already been converted,
// emit set events for everything inside
emitSet(obj)
} else {
var type = typeOf(obj)
Expand All @@ -307,14 +321,20 @@ function observe (obj, rawPath, observer) {
* Cancel observation, turn off the listeners.
*/
function unobserve (obj, path, observer) {

if (!obj || !obj.__observer__) return

path = path ? path + '.' : ''
var proxies = observer.proxies[path]
if (!proxies) return

// turn off listeners
obj.__observer__
.off('get', proxies.get)
.off('set', proxies.set)
.off('mutate', proxies.mutate)

// remove reference
observer.proxies[path] = null
}

Expand Down

0 comments on commit 44aa90e

Please sign in to comment.