Răsfoiți Sursa

no longer need an internal emitter

Evan You 11 ani în urmă
părinte
comite
01e6e9ef77
8 a modificat fișierele cu 125 adăugiri și 187 ștergeri
  1. 0 1
      component.json
  2. 107 24
      src/api/events.js
  3. 2 3
      src/api/lifecycle.js
  4. 1 1
      src/directives/cloak.js
  5. 0 143
      src/emitter.js
  6. 4 6
      src/instance/events.js
  7. 8 5
      src/instance/init.js
  8. 3 4
      src/observer/index.js

+ 0 - 1
component.json

@@ -45,7 +45,6 @@
     "src/directives/text.js",
     "src/directives/transition.js",
     "src/directives/with.js",
-    "src/emitter.js",
     "src/filters/array-filters.js",
     "src/filters/index.js",
     "src/instance/events.js",

+ 107 - 24
src/api/events.js

@@ -1,18 +1,102 @@
+var _ = require('../util')
+
+/**
+ * Listen on the given `event` with `fn`.
+ *
+ * @param {String} event
+ * @param {Function} fn
+ */
+
+exports.$on = function (event, fn) {
+  (this._events[event] || (this._events[event] = []))
+    .push(fn)
+  // increment all parent event count by 1.
+  // pay a small cost here to optimize for $broadcast.
+  var parent = this.$parent
+  while (parent) {
+    parent._eventsCount[event] =
+      (parent._eventsCount[event] || 0) + 1
+    parent = parent.$parent
+  }
+}
+
+/**
+ * Adds an `event` listener that will be invoked a single
+ * time then automatically removed.
+ *
+ * @param {String} event
+ * @param {Function} fn
+ */
+
+exports.$once = function (event, fn) {
+  var self = this
+  function on () {
+    self.$off(event, on)
+    fn.apply(this, arguments)
+  }
+  on.fn = fn
+  this.$on(event, on)
+}
+
 /**
- * Proxy basic event methods on the internal emitter.
+ * Remove the given callback for `event` or all
+ * registered callbacks.
+ *
+ * @param {String} event
+ * @param {Function} fn
  */
 
-;['emit', 'on', 'off', 'once'].forEach(function (method) {
-  var realMethod = method === 'emit'
-    ? 'applyEmit'
-    : method
-  exports['$' + method] = function () {
-    this._emitter[realMethod].apply(
-      this._emitter,
-      arguments
-    )
+exports.$off = function (event, fn) {
+  // all
+  if (!arguments.length) {
+    this._events = {}
+    return
+  }
+  // specific event
+  var cbs = this._events[event]
+  if (!cbs) return
+  if (arguments.length === 1) {
+    this._events[event] = null
+    return
+  }
+  // specific handler
+  var cb
+  var i = cbs.length
+  while (i--) {
+    cb = cbs[i]
+    if (cb === fn || cb.fn === fn) {
+      cbs.splice(i, 1)
+      break
+    }
   }
-})
+}
+
+/**
+ * Trigger an event on self.
+ *
+ * @param {String} event
+ */
+
+exports.$emit = function (event) {
+  this._cancelled = false
+  var cbs = this._events[event]
+  if (cbs) {
+    // avoid leaking arguments:
+    // http://jsperf.com/closure-with-arguments
+    var i = arguments.length - 1
+    var args = new Array(i)
+    while (i--) {
+      args[i] = arguments[i + 1]
+    }
+    cbs = _.toArray(cbs)
+    i = 0
+    for (var l = cbs.length; i < l; i++) {
+      if (cbs[i].apply(this, args) === false) {
+        this._eventCancelled = true
+      }
+    }
+  }
+}
 
 /**
  * Recursively broadcast an event to all children instances.
@@ -21,13 +105,15 @@
  * @param {...*} additional arguments
  */
 
-exports.$broadcast = function () {
+exports.$broadcast = function (event) {
+  // if no child has registered for this event,
+  // then there's no need to broadcast.
+  if (!this._eventsCount[event]) return
   var children = this._children
-  for (var i = 0, l = children.length; i < l; i++) {
-    var child = children[i]
-    var emitter = child._emitter
-    emitter.applyEmit.apply(emitter, arguments)
-    if (!emitter._cancelled) {
+  if (children) {
+    for (var i = 0, l = children.length; i < l; i++) {
+      var child = children[i]
+      child.$emit.apply(child, arguments)
       child.$broadcast.apply(child, arguments)
     }
   }
@@ -41,12 +127,9 @@ exports.$broadcast = function () {
  */
 
 exports.$dispatch = function () {
-  var emitter = this._emitter
-  emitter.applyEmit.apply(emitter, arguments)
-  if (!emitter._cancelled) {
-    var parent = this.$parent
-    if (parent) {
-      parent.$dispatch.apply(parent, arguments)
-    }
+  var parent = this.$parent
+  while (parent) {
+    parent.$emit.apply(parent, arguments)
+    parent = parent.$parent
   }
 }

+ 2 - 3
src/api/lifecycle.js

@@ -35,7 +35,7 @@ exports.$mount = function (el) {
     this._callHook('attached')
     ready.call(this)
   } else {
-    this._emitter.once('hook:attached', ready)
+    this.$once('hook:attached', ready)
   }
 }
 
@@ -133,6 +133,5 @@ exports.$destroy = function (remove) {
   this._isDestroyed = true
   this._callHook('afterDestroy')
   // turn off all instance listeners.
-  this._emitter.off()
-  this._emitter = null
+  this.$off()
 }

+ 1 - 1
src/directives/cloak.js

@@ -4,7 +4,7 @@ module.exports = {
 
   bind: function () {
     var el = this.el
-    this.vm._emitter.once('hook:compiled', function () {
+    this.vm.$once('hook:compiled', function () {
       el.removeAttribute(config.prefix + 'cloak')
     })
   }

+ 0 - 143
src/emitter.js

@@ -1,143 +0,0 @@
-var _ = require('./util')
-
-/**
- * Simple event emitter based on component/emitter.
- *
- * @constructor
- * @param {Object} ctx - the context to call listners with.
- */
-
-function Emitter (ctx) {
-  this._cancelled = false
-  this._ctx = ctx || null
-}
-
-var p = Emitter.prototype
-
-/**
- * Listen on the given `event` with `fn`.
- *
- * @param {String} event
- * @param {Function} fn
- * @return {Emitter}
- */
-
-p.on = function (event, fn) {
-  this._cbs = this._cbs || {}
-  ;(this._cbs[event] || (this._cbs[event] = []))
-    .push(fn)
-  return this
-}
-
-/**
- * Adds an `event` listener that will be invoked a single
- * time then automatically removed.
- *
- * @param {String} event
- * @param {Function} fn
- * @return {Emitter}
- */
-
-p.once = function (event, fn) {
-  var self = this
-  this._cbs = this._cbs || {}
-  function on () {
-    self.off(event, on)
-    fn.apply(this, arguments)
-  }
-  on.fn = fn
-  this.on(event, on)
-  return this
-}
-
-/**
- * Remove the given callback for `event` or all
- * registered callbacks.
- *
- * @param {String} event
- * @param {Function} fn
- * @return {Emitter}
- */
- 
-p.off = function (event, fn) {
-  this._cbs = this._cbs || {}
-  // all
-  if (!arguments.length) {
-    this._cbs = {}
-    return this
-  }
-  // specific event
-  var callbacks = this._cbs[event]
-  if (!callbacks) return this
-  // remove all handlers
-  if (arguments.length === 1) {
-    this._cbs[event] = null
-    return this
-  }
-  // remove specific handler
-  var cb
-  var i = callbacks.length
-  while (i--) {
-    cb = callbacks[i]
-    if (cb === fn || cb.fn === fn) {
-      callbacks.splice(i, 1)
-      break
-    }
-  }
-  return this
-}
-
-/**
- * The internal, faster emit with fixed amount of arguments
- * using Function.call. This emit assumes that callbacks
- * triggered will not modify the callback list being
- * iterated through.
- *
- * @param {Object} event
- * @return {Emitter}
- */
-
-p.emit = function (event, a, b, c, d) {
-  this._cbs = this._cbs || {}
-  var callbacks = this._cbs[event]
-  if (callbacks) {
-    var ctx = this._ctx
-    for (var i = 0, l = callbacks.length; i < l; i++) {
-      callbacks[i].call(ctx, a, b, c, d)
-    }
-  }
-  return this
-}
-
-/**
- * The external emit using Function.apply, used
- * by Vue instance event methods.
- *
- * @param {Object} event
- * @return {Emitter}
- */
-
-p.applyEmit = function (event) {
-  this._cancelled = false
-  this._cbs = this._cbs || {}
-  var callbacks = this._cbs[event]
-  if (callbacks) {
-    // avoid leaking arguments:
-    // http://jsperf.com/closure-with-arguments
-    var i = arguments.length - 1
-    var args = new Array(i)
-    while (i--) {
-      args[i] = arguments[i + 1]
-    }
-    callbacks = _.toArray(callbacks)
-    i = 0
-    for (var l = callbacks.length; i < l; i++) {
-      if (callbacks[i].apply(this._ctx, args) === false) {
-        this._cancelled = true
-      }
-    }
-  }
-  return this
-}
-
-module.exports = Emitter

+ 4 - 6
src/instance/events.js

@@ -8,7 +8,6 @@ var inDoc = require('../util').inDoc
 
 exports._initEvents = function () {
   var options = this.$options
-  var emitter = this._emitter
   var events = options.events
   var methods = options.methods
   if (events) {
@@ -19,7 +18,7 @@ exports._initEvents = function () {
         var handler = typeof handlers[i] === 'string'
           ? methods && methods[handlers[i]]
           : handlers[i]
-        emitter.on(e, handler)
+        this.$on(e, handler)
       }
     }
   }
@@ -30,8 +29,7 @@ exports._initEvents = function () {
  */
 
 exports._initDOMHooks = function () {
-  var emitter = this._emitter
-  emitter.on('hook:attached', function () {
+  this.$on('hook:attached', function () {
     this._isAttached = true
     var children = this._children
     if (!children) return
@@ -42,7 +40,7 @@ exports._initDOMHooks = function () {
       }
     }
   })
-  emitter.on('hook:detached', function () {
+  this.$on('hook:detached', function () {
     this._isAttached = false
     var children = this._children
     if (!children) return
@@ -68,5 +66,5 @@ exports._callHook = function (hook) {
       handlers[i].call(this)
     }
   }
-  this._emitter.emit('hook:' + hook)
+  this.$emit('hook:' + hook)
 }

+ 8 - 5
src/instance/init.js

@@ -1,4 +1,3 @@
-var Emitter = require('../emitter')
 var mergeOptions = require('../util/merge-option')
 
 /**
@@ -17,13 +16,17 @@ exports._init = function (options) {
   options = options || {}
 
   this.$el           = null
-  this.$             = {}
   this.$root         = this.$root || this
-  this._emitter      = new Emitter(this)
-  this._watchers     = Object.create(null)
-  this._userWatchers = Object.create(null)
+  this.$             = {}
+  this._watchers     = {}
+  this._userWatchers = {}
   this._directives   = []
 
+  // events bookkeeping
+  this._events         = {}
+  this._eventsCount    = {}
+  this._eventCancelled = false
+
   // block instance properties
   this._blockStart  =
   this._blockEnd    = null

+ 3 - 4
src/observer/index.js

@@ -18,10 +18,9 @@ var OBJECT = 1
  * object's property keys into getter/setters that
  * collect dependencies and dispatches updates.
  *
- * @constructor
- * @extends Emitter
  * @param {Array|Object} value
  * @param {Number} type
+ * @constructor
  */
 
 function Observer (value, type) {
@@ -190,7 +189,6 @@ p.convert = function (key, val) {
       binding.notify()
     }
   })
-  return binding
 }
 
 /**
@@ -209,8 +207,8 @@ p.convert = function (key, val) {
 p.tryRelease = function () {
   if (!this.parentCount && !this.vmCount) {
     var value = this.value
-    value.__ob__ = null
     if (_.isArray(value)) {
+      value.__ob__.bindings = null
       this.unobserveArray(value)
     } else {
       for (var key in value) {
@@ -220,6 +218,7 @@ p.tryRelease = function () {
         _.define(value, key, val, true)
       }
     }
+    value.__ob__ = null
   }
 }