【问题标题】:AngularJS $q.all() results are nullAngularJS $q.all() 结果为空
【发布时间】:2014-02-14 11:11:53
【问题描述】:

我正在尝试实现 $q.all 来运行一些函数,然后将所有输出返回到最后附加到 .then 的函数中。

目前,promise 看起来它们以正确的顺序调用,并且 $all .then 发生在最后,但是 results 变量返回一个空数组(一个对应于 $q 中的每个 promise .all)

JS Fiddle 可以在 http://jsfiddle.net/QqKuk/120/ 找到,我使用的是 angular 1.0.1

下面是我拥有的代码的简化示例。

这是我的 html,只是用来显示一些调试文本和输出。

<div ng-controller="MyCtrl">
    <p>{{fromThen}}</p>
    <p>{{fromThen2}}</p>
    <p>{{runOrder}}</p>
</div>

这是我的控制器,实际上 logOne、logTwo 和 logThree 不会是相同的功能。

var myApp = angular.module('myApp', []);

function MyCtrl($scope, $q, $timeout) {

var logOne = function (value) {
    $scope.fromThen = $scope.fromThen + value;
    var deffered = $q.defer();
    deffered.promise.then( function() {
            $scope.runOrder = $scope.runOrder + '.logOne()';
            $scope.fromThen = $scope.fromThen + value.toUpperCase();
            deffered.resolve(value);
            return deffered.promise;
    });

    deffered.resolve();
};

var logTwo = function (value) {
    $scope.fromThen = $scope.fromThen + value;
    var deffered = $q.defer();
    deffered.promise.then( function() {
            $scope.runOrder = $scope.runOrder + '.logTwo()';
            $scope.fromThen = $scope.fromThen + value.toUpperCase();
            deffered.resolve(value);
            return deffered.promise;
    });

    deffered.resolve();
};

var logThree = function (value) {
    $scope.fromThen = $scope.fromThen + value;
    var deffered = $q.defer();
    deffered.promise.then( function() {
            $scope.runOrder = $scope.runOrder + '.logThree()';
            $scope.fromThen = $scope.fromThen + value.toUpperCase();
            deffered.resolve(value);
            return deffered.promise;
    });

    deffered.resolve();
};


$scope.fromThen = '';
$scope.fromThen2 = 'No Value';
$scope.runOrder = '';


$q.all([logOne('One'), logTwo('Two'), logThree('Three')])
                    .then(function(results) {
                        $scope.runOrder = $scope.runOrder + '.then';
                        $scope.fromThen2 = results;
                    });

}

我得到的输出是

OneTwoThreeONETWOTHREE [空,空,空] .logOne().logTwo().logThree().then

在我看来,事情是以正确的顺序调用的,所以我很困惑为什么我在返回值中得到空值。我是否错误地使用了 defer.resolve(value)?

我查看了此处的其他一些示例,但我无法弄清楚为什么我没有得到结果。

感谢您提供的任何帮助。由于这也是我的第一篇文章,任何关于我还应该包含(或不需要包含)哪些信息的提示也将不胜感激。

谢谢。 尼尔

【问题讨论】:

    标签: javascript angularjs q


    【解决方案1】:

    您的问题是您没有从日志函数本身返回您的承诺以供$q.all 遵循。你正在解决承诺并将它们返回到某个地方,而不是任何正在倾听的地方。对.then 的调用内部的函数由$q 调用,并且返回值被发送到.then 本身返回的promise 的解析回调。您有前途的功能应采用以下形式:

    var function = doSomthingDeferred(data) {
      var deferred = $q.defer();
      doSomethingDeferredWith(data).then(function(deferredResult) {
        var processedResult = processDeferredResult(deferredResult);
        deferred.resolve(processedResult);
      });
      return deferred.promise;
    }
    

    或者

    var function = doSomthingDeferred(data) {
      return doSomethingDeferredWith(data).then(function(deferredResult) {
        var processedResult = processDeferredResult(deferredResult);
        return processedResult;
      });
    }
    

    在你的情况下,当你doSomethingDeferredWith(data)你时:

    function doSomethingDeferredWith(data) {
      var deferredMore = $q.defer();
      $scope.fromThen += data;
      deferredMore.resolve($scope.fromThen);
    

    这个特定的操作并不真正需要被推迟,它会立即完成,但如果你查询一个基于$http 的服务,那么你会得到你的deferredMore 承诺:

      return deferredMore.promise;
    }
    

    然后,在您完成此操作后,您将获得一些结果作为在 promise 上调用 .then 时引用的函数的参数,就像从 doSomethingDeferredWith 返回的函数一样:

    doSomethingDeferredWith(data).then(function(deferredResult) {
    

    现在,由于$q 的工作方式,对doSomethingDeferredWith(data) 的调用会返回一个promise,.then 会在该promise 上调用,传入的函数会排队,但不会执行,直到当前脚本循环结束。这意味着.then 被调用,函数被排队,然后doSomethingDeferred 继续执行,返回,然后它的调用函数继续执行直到调用堆栈被清除。只有在那之后,$q 才有机会返回并运行所有已解决承诺的回调。

    在您的代码doSomethingDeferred 中,各种log*** 函数实际上并不返回承诺。他们返回undefined。如果您改为返回我们创建的承诺,并将在$q 运行回调而不是在doSomethingDeferred 结束时解决,您将在$q.all 的回调中获取数据。

    要修复您的代码,请将每个日志文件末尾的 deffered.resolve(); 调用更改为 return deffered.promise; 然后,日志函数的返回值不会是 undefined,它们将被承诺$q 可以在所有三个调用完成后立即对所有三个.resolve 调用运行回调,将$scope.runFrom2 值设置为['One','Two','Three'] 数组,因为每个单独的promise 都使用value 解析来自延迟函数的闭包。

    tl;dr 版本

    将每个日志文件末尾的 deffered.resolve(); 调用更改为 return deffered.promise;

    【讨论】:

    • 这正是我所需要的,感谢关于在 doSomethingDeferredWith() 中使用额外延迟的提示,因为这是我要继续做的其他事情。
    • 是的,您通常会将延迟/承诺模式与本身延迟的服务一起使用,例如$http$http 本质上所做的是创建一个新的延迟对象并在底层XmlHttpRequestonreadystatechange 处理程序中解决它。同样重要的是要记住 .then 返回一个 Promise 本身,它在作为参数传入的函数返回时被解析,允许您链接 Promise,甚至是 $q.all 调用。
    猜你喜欢
    • 1970-01-01
    • 2014-02-14
    • 2016-07-12
    • 1970-01-01
    • 1970-01-01
    • 2014-04-05
    • 2018-02-28
    • 2014-02-02
    • 1970-01-01
    相关资源
    最近更新 更多