多个Javascript异步进程完成后执行操作

时间:2016-01-19 15:56:17

标签: javascript angularjs

所以我有一个针对我公司的长运行查询状态页面,它显示了根据longrunners数量+其他标准改变颜色的不同数据库实例的条形图。

问题是,每次调用更新信息时,颜色都会恢复为默认值,并从头开始构建。这是因为我在检索长队数据时使用$ scope.variable对象来保存颜色信息。

我想将其切换为在函数中使用本地标准变量,并且只有在检索完所有数据后,才将此变量赋值给$ scope.variable。

  • 上下文 - 我们的实例被组织成泳道,因此我为泳道颜色和实例颜色创建了一个对象。当所有都被折叠时,你只能看到泳道,所以我需要一种方法让实例颜色冒泡到泳道。

所以它就像这样:

var getLongrunners = function(){

        $scope.longrunnersByInstance = {};

        for (var l = 0; l < $scope.swimlanes.length; l++){
            $scope.slColor[$scope.swimlanes[l].swimlane] = 0;
        }

        for (var j = 0; j < instances.length; j++){
            $scope.longrunnersByInstance[instances[j].instance] = [];
            $scope.instanceColor[instances[j].instance] = 0;

        }



        for (var i = 0; i < instances.length; i++){
            (function(e){
                $http
                    .get('/getLongrunners',{params: {envFlag: '',instance: instances[e].instance}})
                    .then(function(response){
                        var longrunners = response.data;
                        for(var k = 0; k < longrunners.length; k++){
                            $scope.longrunnersByInstance[instances[e].instance].push(longrunners[k]);
                        }

                        if(longrunners.length > $scope.dangerThresh){

                            $scope.instanceColor[instances[e].instance] = 2;

                        }else if(longrunners.length >= $scope.warningThresh){

                            $scope.instanceColor[instances[e].instance] = 1;

                        }

                        if($scope.slColor[instances[e].swimlane] < $scope.instanceColor[instances[e].instance]) {
                            $scope.slColor[instances[e].swimlane] = $scope.instanceColor[instances[e].instance]
                        }
                    },getLongrunnersFail);
            }(i));

所以我希望$ scope.slColor和$ scope.instanceColor成为常规局部变量,直到此循环结束。

我查看了promises,但是在调用.then()之前,似乎只对$ http有用。

有没有办法制作自定义承诺类型架构并包含多个函数,并且只在完成所有内容后返回承诺?

谢谢!

编辑:

最近尝试:

var promises = [];
    var longrunnersByInstance = {};
    var instancesPerf = {};
    var slColor = {};
    var instanceColor = {};

    var promiseTest = function() {

        $scope.longrunnersByInstance = {};

        for (var l = 0; l < $scope.swimlanes.length; l++){
            slColor[$scope.swimlanes[l].swimlane] = 0;
        }

        for (var j = 0; j < instances.length; j++){
            instanceColor[instances[j].instance] = 0;

        }
        instances.forEach(function (instance) {
            promises.push($http
                .get('/getLongrunners', {
                    params: {envFlag: 'bh', instance: instance.instance}
                })
                .then(function (response) {
                    var longrunners = response.data;

                    longrunnersByInstance[instance.instance] = [];

                    for (var k = 0; k < longrunners.length; k++) {
                        longrunnersByInstance[instance.instance].push(longrunners[k]);
                    }

                    if (longrunners.length > $scope.dangerThresh) {

                        instanceColor[instance.instance] = 2;

                    } else if (longrunners.length >= $scope.warningThresh) {

                        instanceColor[instance.instance] = 1;

                    }

                    console.log(instance.instance);

                    if (slColor[instance.swimlane] < instanceColor[instance.instance]) {
                        slColor[instance.swimlane] = instanceColor[instance.instance]
                    }

                    return true;

                }, getLongrunnersFail)
            );

            function getLongrunnersFail(response){
                console.log("getting longrunners failed" + response.status);
            }


            $q.all(promises).then(function () {
                // longrunnersByInstance to $scope

                console.log('calling all promises callback!');

                instances.forEach(function (instance) {
                    $scope.longrunnersByInstance[instance.instance] = longrunnersByInstance[instance.instance];
                });



                // instancesPerf to $scope
                instances.forEach(function (instance) {
                    $scope.instancesPerf[instance.instance] = instancesPerf[instance.instance];
                });

                // slColor to $scope
                instances.forEach(function (instance) {
                    $scope.slColor[instance.instance] = slColor[instance.instance];
                });

                // instanceColor to $scope
                instances.forEach(function (instance) {
                    $scope.instanceColor[instance.instance] = instanceColor[instance.instance];
                });


            }, allPromisesFail);

            function allPromisesFail(){
                console.log("all promises failed")
            }
        });
    };

2 个答案:

答案 0 :(得分:3)

Angular使用$q服务处理promises。

它有一个名为all的函数来处理您遇到的问题类型。

这是一个简单的小提琴来演示它:http://jsfiddle.net/ThomasBurleson/QqKuk/

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

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

    var thenFn = function(value){
        console.log('resolved ', value);
        return value;
    },
    q1 = $scope.q1 = $q.defer(),
    q2 = $scope.q2 = $q.defer(),
    p1 = $scope.q1.promise, 
    p2 = $scope.q2.promise;


    $scope.fromThen = $q.all([
                            p1.then(thenFn), 
                            p2.then(thenFn)
                        ])
                        .then(function(values) {        
                            console.log(values);
                            return values;
                        });

    // Must start the AngularJS digest process
    // to allow $q.resolve() to work properly
    // So use $timeOut() or $apply()

    setTimeout(function () {
        $scope.$apply( function() {            
            console.log('resolving delayed promises');
            q1.resolve({value : 1});
            q2.resolve({value : 2});
        });
    }, 100, this);

    /* 
     *  Alternative approach
     *
    $timeout( function() {
        console.log('resolving delayed promises');
        q1.resolve({value : 1});
        q2.resolve({value : 2});        
    });
    */
}

以下是如何将其应用于您的代码(尚未对其进行测试,因此它只是一个方向,但它应该让您前进):

var promises = [];
for (var i = 0; i < instances.length; i++){

                //$http return a promise, so you can just push it
                promises.push( $http
                .get('/getLongrunners',{params: {envFlag: '',instance: instances[e].instance}}));

}

$q.all(promises).then(function(values){
   //values should contain an array with all the results you got from all the requests, so you can run through it and aggregate the results
});

答案 1 :(得分:2)

Promise是可链接的:当你在一个promise的成功回调中返回一些内容时,你会得到一个新的promise,它会以返回的值解析。
Example from angular documentation ("Chaining Promises" part)

promiseB = promiseA.then(function(result) {
    return result + 1;
});

// promiseB will be resolved immediately after promiseA is resolved and its value
// will be the result of promiseA incremented by 1

因此,在/getLongRunners回调中,您可以返回一个立即解析的值(如true),这样您就可以获得一个在回调完成后立即解决的承诺。如果你收集所有这些&#34;孩子&#34;数组中的promise可以将该数组传递给$.all,并且当所有promise都解析时,即一旦所有回调都完成,它就会解析。

在这里,我用forEach方法替换了for循环并嵌入了立即执行的函数:它更清晰,避免了遇到的闭包问题

var promises = [];
instances.forEach(function(instance, i) {
    promises.push($http
        .get('/getLongrunners', {
            params: {envFlag: '', instance: instances[e].instance}
        })
        .then(function(response) { 
            var longrunners = response.data;
            // whatever you have to do
            return true;
         }, getLongrunnersFail);
 });
 $q.all(promises).then(function() {
     // When you are here, all your callbacks will have been executed
 });