async和sync - angular的承诺问题

Promises issue with async and sync - angular

本文关键字:承诺 问题 angular sync async      更新时间:2023-09-26

在一个移动cordova/angular项目中工作。下面是一个简单的服务调用:

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是异步的,所以当它返回时,for循环的k远远不正确。

我考虑将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;
};

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

如何克服这一点?

听起来你好像遇到了一个叫做"closure over the loop variable"的问题,这里详细讨论了这个问题:

JavaScript闭包内循环-简单的实际例子

但是,在您的情况下,干净的解决方案是将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指出的,避免延迟反模式:

this.getSomeData = function (id) {
    var query = "SELECT * FROM Stuff";
    return $cordovaSQLite.execute(db, query).then(function (res) {
        return res.rows;
    });
};

我就是这样让它工作的。我试着使用@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;
};