使用具有“then”功能的对象解析promise

时间:2013-12-08 16:17:39

标签: angularjs promise

这是一个抽象的问题,因为我现在没有特定的用例。我注意到,如果你通过承诺解决承诺

var deferredA = $q.defer();
var deferredB = $q.defer();
deferredA.promise.then(function(result) {
  // Will get here once promiseB has been resolved.
});
deferredA.resolve(deferredB.promise);

比promiseA实际上没有得到解决,直到promiseB被解析(然后使用promiseB的解析值解析promiseA)。但是,如果我想使用“then”函数解析对象的值,如下所示:

var deferred = $q.defer();
deferred.promise.then(function(result) {
  // Aim is to get here with result = {then:function(){}},
  // as though I had resolved a promise with a non-promise value,
  // but this function is never called
});
deferred.resolve({
  then: function() {
  }
});

然后promiseA从未实际得到解决,因为它假设该值是一个promise,即使在上面的例子中它不是,因为它不是用$ q.defer()创建的。

有一个示例plunkr

http://plnkr.co/edit/Z8XUKzxHtGBKBmgPed2q?p=preview

有解决方法吗?如果是这样,怎么样?

修改:澄清延期/承诺&放入示例“then”回调。

3 个答案:

答案 0 :(得分:5)

解决方案

您传入的then属性会覆盖promise then属性。您想要从角度承诺then函数的成功回调中返回您的对象,如下所示:

$scope.resolvePromise2 = function() {
    deferred2.resolve({
      then: function(successCB) {
        successCB({myResult1:'result1',
                  myResult2:'result2',
                  'then':function() {console.log("got here")}});
      }
    });
  };

现在使用上面的消息调用,您可以调用属性中的then函数:

promise2.then(function(result) {
   //Now we get here
   $scope.messages2.push('Promise 2 then callback. Result is:' + result);
   result.then();
});

这是您更新的working plunker

问题/为什么会这样?

让我们来看看Angular resolve()

resolve: function(val) {
    if (pending) {
      var callbacks = pending;
      pending = undefined;
      value = ref(val);

      if (callbacks.length) {
        nextTick(function() {
          var callback;
          for (var i = 0, ii = callbacks.length; i < ii; i++) {
            callback = callbacks[i];
            value.then(callback[0], callback[1], callback[2]);
          }
        });
      }
    }
  },

查看value = ref(val);后跟value.then(callback[0], callback[1], callback[2]);,我们看到 Angular将then函数附加到承诺作为属性,并且您传递的对象覆盖那个财产。因此,在您的情况下,调用传入的then函数而不是deferred.promise.then(function(result)...

但是 Angular通过三个回调调用您的then函数(成功,错误,通知):value.then(callback[0], callback[1], callback[2]);已保存在var callbacks = pending;

因此,解决方案是在then函数内调用第一个“成功”回调函数,并将您的对象(包括要返回的then属性)传递给它。现在,承诺then被调用并接收您的对象,包括您的then属性

then: function(successCB) {
   successCB({myResult1:'result1',
              myResult2:'result2',
              'then':function() {console.log("got here")}});
}

答案 1 :(得分:2)

你说{then:function(){...}}不是承诺。那么,相应的承诺A +规范。

规范声明promises应该是可互操作的,如果一个promise用一个thenable对象解决,或者一个promise的onFulfill回调返回了一个,那就说了。一旦onFulfill返回的promise或作为参数传递给resolve方法的promise得到解决,第一个promise的then方法返回的promise将被解析。

所以你的承诺永远不会解决,因为你的obable对象永远不会被“解析”,并且从不调用它的onFulfill回调。

这有点令人困惑,但让我们看看练习。

var deferred = $q.defer();
deferred.promise.then(function(result) {
     // A promise should not be resolved with another
});

deferred.resolve({
    then: function() {
    }
});

deferred的resolve方法将会看到你对象的then方法,然后思考:“呃,姐姐的承诺,我会尽快得到解决”。 所以它会通过回调来调用你的then函数来实际解决你的承诺。

这样:

yourThenable.then(function(spectedData){ 
     // Your promise will resolve as soon as this callback gets called
     // But your then function doesnt call the onFulfill callback
     // Thats why it never resolves
}, function(spectedData){ 
     // Also if this second parameter gets called your promise will be rejected
});

我不知道你为什么要这样做,但你不应该用一个可靠的人来解决这个承诺。 你可以用另一种方式思考你想要的东西。

这是我能想到的最简单的方法:

deferred.resolve([{
   then: function() {
   }
}]);

resolve方法将查找then方法,但是现在你的对象不是一个可用的,那个数组的0索引是。

deferred.promise.then(function(result) {
    // Now you have a result that is a Array
    // And the index 0 is your thenable object
});

但是,在继续这样做之前,你应该再三考虑。

答案 2 :(得分:0)

我得出的结论是,这是不可能的。 您只能通过将对象包装在另一个没有一个对象的对象中来确保您没有then属性:

var deferred = $q.defer();
deferred.promise.then(function(result) {
  // Aim is to get here with result = {then:function(){}},
  // as though I had resolved a promise with a non-promise value,
  // but this function is never called
  result.result.then
}); 
deferred.resolve({ result: {
  then: function() {}
}});