Răsfoiți Sursa

observer cleanup

Evan You 12 ani în urmă
părinte
comite
44aa90e54c
2 a modificat fișierele cu 37 adăugiri și 17 ștergeri
  1. 2 2
      src/directives/repeat.js
  2. 35 15
      src/observer.js

+ 2 - 2
src/directives/repeat.js

@@ -1,5 +1,4 @@
 var Observer   = require('../observer'),
-    Emitter    = require('../emitter'),
     utils      = require('../utils'),
     config     = require('../config'),
     transition = require('../transition'),
@@ -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
@@ -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)

+ 35 - 15
src/observer.js

@@ -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
@@ -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 {
@@ -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)
@@ -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
 }