Angularjs 用一个带“的对象解决承诺”;然后";功能

Angularjs 用一个带“的对象解决承诺”;然后";功能,angularjs,promise,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); 在允诺人被解决之前,允诺人实际上

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

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);
在允诺人被解决之前,允诺人实际上是不会被解决的(然后允诺人以允诺人的决议的价值被解决)。但是,如果我想用带有“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实际上从未得到解决,因为它假设该值是一个承诺,即使在上面的示例中它不是,例如,它不是用$q.defer()创建的。有一个例子是plunkr

有办法解决这个问题吗?如果是,怎么做

编辑:澄清延迟/承诺并加入示例“然后”回调。

解决方案 您传递的
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();
});
这是你的最新消息

问题/原因让我们看看角度:


你说过{then:function(){…}}不是承诺。好吧,根据A+规范的承诺

该规范规定承诺应该是可互操作的,也就是说,如果一个承诺是用一个thenable对象解析的,或者如果一个承诺的onfully回调返回一个thenable。一旦onFulfill返回的承诺或作为参数传递给resolve方法的承诺得到解决,第一个承诺的then方法返回的承诺就会得到解决

因此,您的承诺永远不会解决,因为您的thenable对象永远不会得到“解决”,也永远不会调用其onfully回调

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

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

deferred.resolve({
    then: function() {
    }
});
延迟的解决方法将看到你的对象的方法,并认为:“嗯,一个姐妹的承诺,我会得到解决,一旦它得到第一”。 因此,它将使用回调调用您的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方法,但现在您的对象不是thenable,该数组的0索引为

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

但是,在继续这样做之前,你真的应该三思而后行。

我得出结论,这是不可能的。 只有将对象包装到另一个对象中而不包含属性,才能确保没有
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() {}
}});

在调用resolve之前从对象中删除then函数,然后重新添加?目的是能够使用包含“then”函数的对象解析承诺。想要使用承诺解析值的函数可能与生成+解析承诺的函数位于完全不同的代码部分,因此我认为这是不可能的。有趣的是,它没有检测到
$q.defer().promise
的实例。也许这是一个bug…这最终得到的是解析值“result”,而不是“then”successCallback中的对象{then:function(){},我想知道这是可能的。也许一个更现实的例子是,如果值中有其他一些数据/函数,比如{myResult1:'result1',myResult2:'result2',然后:function(){}:我在寻找回调中可用的myResult1,myResult2,然后所有数据/函数。您是否希望包含
然后
,以获得不同的承诺?或者你认为这是递归的?如果resolve()调用的
then
包含另一个
then
函数,则递归的终止条件是什么?如果没有递归,我想这些都不是。有一些异步操作生成一个对象,该对象包含一个
然后
键,该键的值是一个函数。根据我之前的评论,对象中可能还有其他键。目的是将此对象用作承诺的完全解决价值。您可以使用
{'myResult1':'result1','myResult2':'result2'}
作为解析值,但是如果您想将
然后
作为函数包含
{'myResult1':'result1','myResult2':'result2','then':function(){}
,那么这将停止解析承诺,正如最初的解释一样。谢谢-这很有帮助。我更新了答案(和plunker),并希望改进解释。解释起来有点棘手,因为你的
then
属性和角度
then
属性都在相互作用。我看到了:它做了我想要的。谢谢
deferred.promise.then(function(result) {
    // Now you have a result that is a Array
    // And the index 0 is your thenable object
});
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() {}
}});