Evan You 11 anni fa
parent
commit
c0d22e8cae

+ 5 - 15
src/api/data.js

@@ -70,28 +70,18 @@ exports.$delete = function (key) {
 
 exports.$watch = function (exp, cb, deep, immediate) {
   var vm = this
-  var key = deep ? exp + '**deep**' : exp
-  var watcher = vm._userWatchers[key]
   var wrappedCb = function (val, oldVal) {
     cb.call(vm, val, oldVal)
   }
-  if (!watcher) {
-    watcher = vm._userWatchers[key] =
-      new Watcher(vm, exp, wrappedCb, {
-        deep: deep,
-        user: true
-      })
-  } else {
-    watcher.addCb(wrappedCb)
-  }
+  var watcher = new Watcher(vm, exp, wrappedCb, {
+    deep: deep,
+    user: true
+  })
   if (immediate) {
     wrappedCb(watcher.value)
   }
   return function unwatchFn () {
-    watcher.removeCb(wrappedCb)
-    if (!watcher.active) {
-      vm._userWatchers[key] = null
-    }
+    watcher.teardown()
   }
 }
 

+ 13 - 28
src/directive.js

@@ -78,27 +78,16 @@ p._bind = function (def) {
           }
         }
       : function () {} // noop if no update is provided
-    // use raw expression as identifier because filters
-    // make them different watchers
-    var watcher = this.vm._watchers[this.raw]
-    // v-repeat always creates a new watcher because it has
-    // a special filter that's bound to its directive
-    // instance.
-    if (!watcher || this.name === 'repeat') {
-      watcher = this.vm._watchers[this.raw] = new Watcher(
-        this.vm,
-        this._watcherExp,
-        update, // callback
-        {
-          filters: this.filters,
-          twoWay: this.twoWay,
-          deep: this.deep
-        }
-      )
-    } else {
-      watcher.addCb(update)
-    }
-    this._watcher = watcher
+    var watcher = this._watcher = new Watcher(
+      this.vm,
+      this._watcherExp,
+      update, // callback
+      {
+        filters: this.filters,
+        twoWay: this.twoWay,
+        deep: this.deep
+      }
+    )
     if (this._initValue != null) {
       watcher.set(this._initValue)
     } else if (this.update) {
@@ -182,17 +171,13 @@ p._checkParam = function (name) {
 
 p._teardown = function () {
   if (this._bound) {
+    this._bound = false
     if (this.unbind) {
       this.unbind()
     }
-    var watcher = this._watcher
-    if (watcher && watcher.active) {
-      watcher.removeCb(this._update)
-      if (!watcher.active) {
-        this.vm._watchers[this.raw] = null
-      }
+    if (this._watcher) {
+      this._watcher.teardown()
     }
-    this._bound = false
     this.vm = this.el = this._watcher = null
   }
 }

+ 3 - 9
src/instance/compile.js

@@ -118,13 +118,9 @@ exports._destroy = function (remove, deferCleanup) {
     // splicing the directives
     this._unlinkFn(true)
   }
-  // teardown all user watchers.
-  var watcher
-  for (i in this._userWatchers) {
-    watcher = this._userWatchers[i]
-    if (watcher) {
-      watcher.teardown()
-    }
+  i = this._watchers.length
+  while (i--) {
+    this._watchers[i].teardown()
   }
   // remove reference to self on $el
   if (this.$el) {
@@ -152,8 +148,6 @@ exports._cleanup = function () {
   this._data.__ob__.removeVm(this)
   this._data =
   this._watchers =
-  this._userWatchers =
-  this._watcherList =
   this.$el =
   this.$parent =
   this.$root =

+ 1 - 3
src/instance/init.js

@@ -20,9 +20,7 @@ exports._init = function (options) {
   this.$root         = options._root || this
   this.$             = {} // child vm references
   this.$$            = {} // element references
-  this._watcherList  = [] // all watchers as an array
-  this._watchers     = {} // internal watchers as a hash
-  this._userWatchers = {} // user watchers as a hash
+  this._watchers     = [] // all watchers as an array
   this._directives   = [] // all directives
 
   // a flag to avoid this being observed

+ 2 - 2
src/instance/scope.js

@@ -123,9 +123,9 @@ exports._unproxy = function (key) {
  */
 
 exports._digest = function () {
-  var i = this._watcherList.length
+  var i = this._watchers.length
   while (i--) {
-    this._watcherList[i].update()
+    this._watchers[i].update()
   }
   var children = this._children
   i = children.length

+ 6 - 40
src/watcher.js

@@ -23,14 +23,15 @@ var uid = 0
 
 function Watcher (vm, expression, cb, options) {
   this.vm = vm
-  vm._watcherList.push(this)
+  vm._watchers.push(this)
   this.expression = expression
-  this.cbs = [cb]
+  this.cb = cb
   this.id = ++uid // uid for batching
   this.active = true
   options = options || {}
   this.deep = !!options.deep
   this.user = !!options.user
+  this.twoWay = !!options.twoWay
   this.deps = []
   this.newDeps = []
   // setup filters if any.
@@ -174,46 +175,11 @@ p.run = function () {
     ) {
       var oldValue = this.value
       this.value = value
-      var cbs = this.cbs
-      for (var i = 0, l = cbs.length; i < l; i++) {
-        cbs[i](value, oldValue)
-        // if a callback also removed other callbacks,
-        // we need to adjust the loop accordingly.
-        var removed = l - cbs.length
-        if (removed) {
-          i -= removed
-          l -= removed
-        }
-      }
+      this.cb(value, oldValue)
     }
   }
 }
 
-/**
- * Add a callback.
- *
- * @param {Function} cb
- */
-
-p.addCb = function (cb) {
-  this.cbs.push(cb)
-}
-
-/**
- * Remove a callback.
- *
- * @param {Function} cb
- */
-
-p.removeCb = function (cb) {
-  var cbs = this.cbs
-  if (cbs.length > 1) {
-    cbs.$remove(cb)
-  } else if (cb === cbs[0]) {
-    this.teardown()
-  }
-}
-
 /**
  * Remove self from all dependencies' subcriber list.
  */
@@ -224,14 +190,14 @@ p.teardown = function () {
     // we can skip this if the vm if being destroyed
     // which can improve teardown performance.
     if (!this.vm._isBeingDestroyed) {
-      this.vm._watcherList.$remove(this)
+      this.vm._watchers.$remove(this)
     }
     var i = this.deps.length
     while (i--) {
       this.deps[i].removeSub(this)
     }
     this.active = false
-    this.vm = this.cbs = this.value = null
+    this.vm = this.cb = this.value = null
   }
 }
 

+ 5 - 16
test/unit/specs/api/data_spec.js

@@ -89,23 +89,12 @@ describe('Data API', function () {
     vm.a = 2
     nextTick(function () {
       expect(spy).toHaveBeenCalledWith(4, 3)
-      // reuse same watcher
-      var spy2 = jasmine.createSpy()
-      var unwatch2 = vm.$watch('a + b.c', spy2)
-      expect(vm._watcherList.length).toBe(1)
-      vm.b = { c: 3 }
+      // unwatch
+      unwatch()
+      vm.a = 3
       nextTick(function () {
-        expect(spy).toHaveBeenCalledWith(5, 4)
-        expect(spy2).toHaveBeenCalledWith(5, 4)
-        // unwatch
-        unwatch()
-        unwatch2()
-        vm.a = 3
-        nextTick(function () {
-          expect(spy.calls.count()).toBe(3)
-          expect(spy2.calls.count()).toBe(1)
-          done()
-        })
+        expect(spy.calls.count()).toBe(2)
+        done()
       })
     })
   })

+ 2 - 4
test/unit/specs/api/lifecycle_spec.js

@@ -161,8 +161,6 @@ if (_.inBrowser) {
         expect(data.__ob__.vms.length).toBe(0)
         expect(vm._isDestroyed).toBe(true)
         expect(vm._watchers).toBeNull()
-        expect(vm._userWatchers).toBeNull()
-        expect(vm._watcherList).toBeNull()
         expect(vm.$el).toBeNull()
         expect(vm.$parent).toBeNull()
         expect(vm.$root).toBeNull()
@@ -236,8 +234,8 @@ if (_.inBrowser) {
           data: { a: 1 }
         })
         vm.$watch('a', function () {})
-        var dirWatcher = vm._watcherList[0]
-        var userWatcher = vm._watcherList[1]
+        var dirWatcher = vm._watchers[0]
+        var userWatcher = vm._watchers[1]
         vm.$destroy()
         expect(dirWatcher.active).toBe(false)
         expect(userWatcher.active).toBe(false)

+ 0 - 21
test/unit/specs/directive_spec.js

@@ -162,25 +162,4 @@ describe('Directive', function () {
     expect(def.update).toHaveBeenCalled()
   })
 
-  it('reuse the same watcher', function (done) {
-    var d = new Directive('test', el, vm, {
-      expression: 'a',
-    }, def)
-    var d2 = new Directive('test', el, vm, {
-      expression: 'a',
-    }, def)
-    expect(vm._watcherList.length).toBe(1)
-    expect(d._watcher).toBe(d2._watcher)
-    d2._teardown()
-    expect(d2._watcher).toBeNull()
-    expect(vm._watcherList.length).toBe(1)
-    vm.a = 2
-    nextTick(function () {
-      expect(def.update).toHaveBeenCalledWith(2, 1)
-      d._teardown()
-      expect(vm._watcherList.length).toBe(0)
-      done()
-    })
-  })
-
 })

+ 2 - 2
test/unit/specs/directives/model_spec.js

@@ -232,9 +232,9 @@ if (_.inBrowser) {
         expect(opts[0].selected).toBe(true)
         expect(opts[1].selected).toBe(false)
         // should teardown option watcher when unbind
-        expect(vm._watcherList.length).toBe(2)
+        expect(vm._watchers.length).toBe(2)
         vm._directives[0]._teardown()
-        expect(vm._watcherList.length).toBe(0)
+        expect(vm._watchers.length).toBe(0)
         done()
       })
     })

+ 0 - 2
test/unit/specs/instance/init_spec.js

@@ -24,9 +24,7 @@ describe('Instance Init', function () {
     expect(stub.$el).toBe(null)
     expect(stub.$root).toBe(stub)
     expect(stub.$).toBeTruthy()
-    expect(stub._watcherList).toBeTruthy()
     expect(stub._watchers).toBeTruthy()
-    expect(stub._userWatchers).toBeTruthy()
     expect(stub._directives).toBeTruthy()
     expect(stub._events).toBeTruthy()
     expect(stub._eventsCount).toBeTruthy()

+ 1 - 49
test/unit/specs/watcher_spec.js

@@ -315,39 +315,6 @@ describe('Watcher', function () {
     })
   })
 
-  it('add callback', function (done) {
-    var watcher = new Watcher(vm, 'a', spy)
-    var spy2 = jasmine.createSpy()
-    watcher.addCb(spy2)
-    vm.a = 99
-    nextTick(function () {
-      expect(spy).toHaveBeenCalledWith(99, 1)
-      expect(spy2).toHaveBeenCalledWith(99, 1)
-      done()
-    })
-  })
-
-  it('remove callback', function (done) {
-    // single, should equal teardown
-    var fn = function () {}
-    var watcher = new Watcher(vm, 'a', fn)
-    watcher.removeCb(fn)
-    expect(watcher.active).toBe(false)
-    expect(watcher.vm).toBe(null)
-    expect(watcher.cbs).toBe(null)
-    // multiple
-    watcher = new Watcher(vm, 'a', spy)
-    var spy2 = jasmine.createSpy()
-    watcher.addCb(spy2)
-    watcher.removeCb(spy)
-    vm.a = 234
-    nextTick(function () {
-      expect(spy).not.toHaveBeenCalled()
-      expect(spy2).toHaveBeenCalledWith(234, 1)
-      done()
-    })
-  })
-
   it('teardown', function (done) {
     var watcher = new Watcher(vm, 'b.c', spy)
     watcher.teardown()
@@ -355,7 +322,7 @@ describe('Watcher', function () {
     nextTick(function () {
       expect(watcher.active).toBe(false)
       expect(watcher.vm).toBe(null)
-      expect(watcher.cbs).toBe(null)
+      expect(watcher.cb).toBe(null)
       expect(spy).not.toHaveBeenCalled()
       done()
     })
@@ -372,21 +339,6 @@ describe('Watcher', function () {
     config.async = true
   })
 
-  it('handle a cb that triggers removeCb', function () {
-    var watcher = new Watcher(vm, 'a', spy)
-    watcher.addCb(function () {
-      watcher.removeCb(spy)
-    })
-    watcher.addCb(function () {})
-    config.async = false
-    expect(function () {
-      vm.a = 2
-    }).not.toThrow()
-    config.async = true
-    expect(spy).toHaveBeenCalled()
-    expect(watcher.cbs.length).toBe(2)
-  })
-
   it('warn getter errors', function () {
     var watcher = new Watcher(vm, 'd.e + c', spy)
     expect(hasWarned(_, 'Error when evaluating expression')).toBe(true)