如何正确使用promises和$ q来处理Angular中的异步调用?

时间:2014-10-09 13:58:33

标签: javascript json angularjs asynchronous angular-promise

我有以下结构的代码(伪代码): 页面初始化(应用程序启动): a] getDateRange - >获取日期范围数组(例如包含10个项目的数组) b] getResultFromDatabaseForDateRange - >每次调用后返回JSON对象的Assync任务

我想在每个循环中调用 b 方法,并将每个JSON数组对象存储返回到类全局变量中。收到 b 的所有回复后,我想将整个填充的对象设置为范围。

有人能给我一个例子,我怎样才能以正确的方式做到这一点?

感谢您的任何建议。

我试图通过这种方式做到这一点,但它不起作用(代码因长度而简化):

 $scope.getDateRange = function(direction) {
            console.log('Trying to set date range for ' +direction);
            switch(direction) {
                case 'today':
                    console.log("Trying to set date range for this week - "+countOfWeeksInPast+" weeks");


                    dateTo = moment().day(7).format('YYYY-MM-DD');
                    dateFrom = moment().day(1).format('YYYY-MM-DD');
                    console.log(dateTo);
                    console.log(dateFrom);

                    // CREATE THIS WEEK - 10 WEEKS RANGE IN PAST
                    for (var i = 0; i < countOfWeeksInPast; i++) {
                        var row = {};
                        if(i==0) {
                            row.ID = i;
                            row.DATE_TO = dateTo;
                            row.DATE_FROM = dateFrom;
                            dateRanges.push(row);
                        } else {
                            row.ID = i;
                            row.DATE_TO = dateTo = moment(dateTo).subtract(7, 'days').format('YYYY-MM-DD');
                            row.DATE_FROM = dateFrom = moment(dateFrom).subtract(7, 'days').format('YYYY-MM-DD');
                            dateRanges.push(row);
                        }
                    }


                    $scope.getResultFromDatabaseForDateRange('create_new').then(function(result){
                        // THIS GIVES THE VALUE:
                        //alert("Result is" + JSON.stringify(result));
                        console.log("Returned Result is: " + JSON.stringify(result));
                        //return result;
                    }, function(e){
                        $ionicLoading.show({
                            template: $translate.instant('ERROR_DATABASE'),
                            duration:1000
                        });
                    });

            }
        };

        $scope.getResultFromDatabaseForDateRange = function(listAction) {
            console.log('trying to get data for selected date ranges');
            // SHOW LOADING MESSAGE
            $ionicLoading.show({
                template: 'Loading data'
            });

            var deferred = $q.defer();


            // INSTANTIATE DB CONNECTION
            db = window.sqlitePlugin.openDatabase({name:"callplanner"});
            var ic=0;

            for(ic; ic < dateRanges.length; ic++) {
                var sqlQuery =
                    "SELECT '"+dateRanges[ic].DATE_FROM+"' as DATE_FROM, "+
                    " '"+dateRanges[ic].DATE_TO+"' as DATE_TO, "+
                    " COUNT(*) AS DIALS_CNT, "+
                    " SUM(CASE WHEN dc.call_result = '"+CALL_RESULT_STATE_APPT+"' THEN 1 ELSE 0 END) AS '"+APPT_CNT+"', "+
                    " SUM(CASE WHEN dc.call_result = '"+CALL_RESULT_STATE_CONV_NO_APPT+"' THEN 1 ELSE 0 END) AS '"+CONVERS_CNT+"' , "+
                    " SUM(CASE WHEN dc.call_result = '"+CALL_RESULT_STATE_CANNOT_REACH+"' THEN 1 ELSE 0 END) AS '"+CANNOT_REACH_CNT+"' "+
                    " FROM "+DIALED_CALLS_TABLE+" dc "+
                    " WHERE  dc.date BETWEEN '"+dateRanges[ic].DATE_FROM+"' AND '"+dateRanges[ic].DATE_TO+"';";

                console.log(sqlQuery);

                db.transaction(function(tx) {
                    // init empty array for results
                    tx.executeSql(sqlQuery, [], function(tx,results){
                        for (var i=0; i < results.rows.length; i++){
                            row = results.rows.item(i);
                            //Udpate date for writeout
                            //row.DATE = moment(row.DATE).format('ddd DD.M');
                            //row.SUCCES_RATE = DialsCompute.computeSuccessRateDaily(row);
                            listData.push(row);
                            console.log("row is " + JSON.stringify(row));

                        }
                        console.log(JSON.stringify(listData));
                    });

                },function (e) {
                    console.log("ERROR: " + e.message);
                    deferred.reject(e);
                });

            }
            deferred.resolve(row);
            $ionicLoading.hide();
            return deferred.promise;
        };

2 个答案:

答案 0 :(得分:0)

您需要计算处理的行数,当它等于需要读取的行数时,您应该解决您的承诺。所以在你的情况下:

var numberOfProcessed = 0;
for(ic; ic < dateRanges.length; ic++) {
                var sqlQuery ="..."

                db.transaction(function(tx) {
                    // init empty array for results
                    tx.executeSql(sqlQuery, [], function(tx,results){
                        //process your result from sql
                        numberOfProcessed++;
                        if(numberOfProcessed == dateRanges.length){
                          deferred.resolve(resultObject); // resolve your promise when you are sure you handled everything
                        }
                        console.log(JSON.stringify(listData));
                    });

                },function (e) {
                    console.log("ERROR: " + e.message);
                    deferred.reject(e);
                });

            }

btw getResultFromDatabaseForDateRange需要成为服务,业务逻辑或与后端服务等的连接的一部分,不应成为控制器的一部分。

答案 1 :(得分:0)

对于我的新闻自动收报机指令,我创建了以下内容:

   //method call
     fetchData($scope.verbs).then(function (messageModel) {
                $scope.messageModel = messageModel;
                $scope.toggleTimer();
            }, function (data) {
                $element.css("display", "none");
                $log.error("error: " + data.message);
            });

  //helper functions
        function fetchData(verbs) {
            return checkRequiredVerbs(verbs)
                .then(getDataFromSource)
                .then(prepareMessages);
        };

        function checkRequiredVerbs(verbs) {
            var deferred = $q.defer(),
                arrRequiredVerbs = configManager.baseUrl.split(/\/:/g);

            if (angular.isObject(verbs)) {
                for (var i = 1; i < arrRequiredVerbs.length; i++) {
                    if (!verbs.hasOwnProperty(arrRequiredVerbs[i])) {
                        deferred.reject({message: "Verb '" + arrRequiredVerbs[i] + "' is unknown"});
                        break;
                    }
                }
                deferred.resolve(verbs);
            } else {
                deferred.reject({message: "Wrong verb syntax!"});
            }

            return deferred.promise;
        };

        function getDataFromSource(verbs) {
            return messageLoaderFactory.query(verbs).$promise;
        };

        function prepareMessages(messageModel) {
            var deferred = $q.defer(),
                tmpMessageModel = [];

            for (var i = 0; i < messageModel.length; i++) {
                messageModel[i].visible = (i === 0);
            }

            deferred.resolve(messageModel);

            return deferred.promise;
        };
    }}

在我从服务中获取数据之前,我必须检查输入参数。首先会调用函数fetchData。在此函数内部,将调用checkRequiredVerbs函数并返回Promise。此承诺将转移到下一个函数getDataFromSource并返回另一个Promise。最后,将调用函数prepareMessages。当某些事情发生时,所有行动都会停止,新闻自动收报机将被隐藏。

完整的项目可以找到here