Promise问题与异步和同步 - 角度

时间:2016-09-06 10:32:27

标签: javascript angularjs cordova promise angular-promise

使用移动cordova /角项目。以下是一个简单的服务电话:

this.getSomeData = function (businessId) {
    var deferred = $q.defer();
    var query = "SELECT * FROM Stuff";
    $cordovaSQLite.execute(db, query).then(function (res) {
        deferred.resolve(res.rows);
    }, function (err) {
        deferred.reject(err);
    });

    return deferred.promise;
};

问题很简单:

for (var k = 0; k < count; k++) {

    myService.getSomeData($scope.model.stuff[k].id, k).then(function (data) {
        // whatever
    }
);

getSomeData是异步的,所以当它返回时,k周期的for远非正确。

我想过将k作为参数传递给服务方法:

for (var k = 0; k < count; k++) {

    myService.getSomeData($scope.model.stuff[k].id, k).then(function (data) {
        // whatever
    }
);

并相应地更改服务方法:

this.getSomeData = function (id, index) {
    var deferred = $q.defer();
    var query = "SELECT * FROM Stuff";
    $cordovaSQLite.execute(db, query).then(function (res) {
        deferred.resolve(res.rows, index);
    }, function (err) {
        deferred.reject(err);
    });

    return deferred.promise;
};

但是第二个参数被忽略,并且总是未定义。

如何克服这个问题?

2 个答案:

答案 0 :(得分:0)

听起来你遇到了一个叫做“关闭循环变量”的问题,这个问题在这里有详细讨论:

JavaScript closure inside loops – simple practical example

但是,在您的情况下,干净的解决方案是将Array#map$q.all()合并:

$q.all($scope.model.visits.map(function (stuff) {
    return myService.getSomeData(stuff.id);
})).then(function (results) {
    // results is an array of the results of all the calls to getSomeData() in the correct order
});

另外,正如Bergi指出的那样,避免使用deferred antipattern

this.getSomeData = function (id) {
    var query = "SELECT * FROM Stuff";

    return $cordovaSQLite.execute(db, query).then(function (res) {
        return res.rows;
    });
};

答案 1 :(得分:0)

这就是我的工作方式。我尝试使用@ JLRishe的建议,但它不起作用。事实证明,我设法将多个参数传递给服务方法并返回到控制器(通过构建一个对象而不是包含我需要的多个参数)。

myService.getSomeData().then(
    function (stuff) {
        // whatever
    }
).then(function () {
    for (var i = 0; i < $scope.model.stuff.length; i++) {

        // HERE I SEND TWO PARAMETERS TO THE SERVICE METHOD
        myService.getSomeMoreData($scope.model.stuff[i].id, i).then(
            function (data) {
                // whatever
            }
        );
    }
});

this.getSomeMoreData = function (id, index) {
    var deferred = $q.defer();
    var query = "SELECT * FROM stuff";

    $cordovaSQLite.execute(db, query).then(function (res) {
        var moreStuff = [];

        for (var i = 0; i < res.rows.length; i++) {
            var junk = res.rows.item(i);
            moreStuff.push(junk);

        }

        // HERE I RESOLVE AN OBJECT INSTEAD OF TWO PARAMETERS
        deferred.resolve({
            moreStuff: moreStuff,
            index: index
        });

    }, function (err) {
        deferred.reject(err);
    });

    return deferred.promise;
};