Просмотр исходного кода

invalid pending async component callbacks

Evan You 11 лет назад
Родитель
Сommit
da9eba3046
2 измененных файлов с 36 добавлено и 8 удалено
  1. 25 8
      src/directives/component.js
  2. 11 0
      src/instance/misc.js

+ 25 - 8
src/directives/component.js

@@ -36,6 +36,8 @@ module.exports = {
         // extract inline template as a DocumentFragment
         this.template = _.extractContent(this.el, true)
       }
+      // pending callback for async component resolution
+      this._pendingCb = null
       // if static, build right now.
       if (!this._isDynamicLiteral) {
         this.resolveCtor(this.expression, _.bind(function () {
@@ -63,13 +65,27 @@ module.exports = {
 
   resolveCtor: function (id, cb) {
     var self = this
-    // TODO handle update/teardown before the component
-    // is actually resolved
-    this.vm._resolveComponent(id, function (ctor) {
-      self.ctorId = id
-      self.Ctor = ctor
-      cb()
-    })
+    var pendingCb = this._pendingCb = function (ctor) {
+      if (!pendingCb.invalidated) {
+        self.ctorId = id
+        self.Ctor = ctor
+        cb()
+      }
+    }
+    this.vm._resolveComponent(id, pendingCb)
+  },
+
+  /**
+   * When the component changes or unbinds before an async
+   * constructor is resolved, we need to invalidate its
+   * pending callback.
+   */
+
+  invalidatePending: function () {
+    if (this._pendingCb) {
+      this._pendingCb.invalidated = true
+      this._pendingCb = null
+    }
   },
 
   /**
@@ -144,9 +160,9 @@ module.exports = {
    */
 
   update: function (value) {
+    this.invalidatePending()
     if (!value) {
       // just remove current
-      this.unbuild()
       this.remove(this.childVM)
       this.unsetCurrent()
     } else {
@@ -224,6 +240,7 @@ module.exports = {
    */
 
   unbind: function () {
+    this.invalidatePending()
     this.unbuild()
     // destroy all keep-alive cached instances
     if (this.cache) {

+ 11 - 0
src/instance/misc.js

@@ -17,6 +17,17 @@ exports._applyFilter = function (id, args) {
   return (filter.read || filter).apply(this, args)
 }
 
+/**
+ * Resolve a component, depending on whether the component
+ * is defined normally or using an async factory function.
+ * Resolves synchronously if already resolved, otherwise
+ * resolves asynchronously and replaces the factory with
+ * the resolved component.
+ *
+ * @param {String} id
+ * @param {Function} cb
+ */
+
 exports._resolveComponent = function (id, cb) {
   var registry = this.$options.components
   var raw = registry[id]