Angularjs angular$q,如何在for循环内部和之后链接多个承诺

Angularjs angular$q,如何在for循环内部和之后链接多个承诺,angularjs,promise,angular-promise,deferred,Angularjs,Promise,Angular Promise,Deferred,我希望有一个for循环,每次迭代调用异步函数 在for循环之后,我想执行另一个代码块,但不是在for循环中以前的所有调用都被解析之前 目前我的问题是,for循环后的代码块要么在所有异步调用完成之前执行,要么根本不执行 带有FOR循环的代码部分及其后面的代码块(有关完整代码,请参阅): […] 函数outerFunction($q,$scope){ var defer=$q.defer(); readSome($q,$scope){ var promise=writeSome($q,$scope.

我希望有一个for循环,每次迭代调用异步函数

在for循环之后,我想执行另一个代码块,但不是在for循环中以前的所有调用都被解析之前

目前我的问题是,for循环后的代码块要么在所有异步调用完成之前执行,要么根本不执行

带有FOR循环的代码部分及其后面的代码块(有关完整代码,请参阅):

[…]
函数outerFunction($q,$scope){
var defer=$q.defer();
readSome($q,$scope){
var promise=writeSome($q,$scope.testArray[0])
对于(变量i=1;i<$scope.testArray.length;i++){
那么(
bind(null,writeSome,$q,$scope.testArray[i])
);                                  
} 
//在for循环中的所有调用完成之前,不得调用此函数
promise=promise.then(函数(){
返回writeSome($q,“finish”)。然后(function(){
控制台日志(“解析”);
//在一切都完成后在这里解决,耶!
defer.resolve();
});   
});        
});   
回报、承诺;
}
我创建了一个JSFIDLE,可以在这里找到

目前看来执行顺序还不错(请参阅控制台输出)

我的猜测是,这仅仅是因为每个函数调用都会立即返回,而不做任何实际工作。我尝试使用setTimeout延迟defer.resolve,但失败(即,最后一个代码块从未执行)。您可以在小提琴的outcommented块中看到它

当我使用写文件和读文件的实际函数时,最后一个代码块在最后一个写操作完成之前执行,这不是我想要的

当然,错误可能出现在其中一个读/写函数中,但我想验证我在这里发布的代码是否没有问题。

您需要使用的是,它将多个承诺组合成一个,只有在所有承诺都得到解决时才能解决

在您的情况下,您可以执行以下操作:

function outerFunction() {

    var defer = $q.defer();
    var promises = [];

    function lastTask(){
        writeSome('finish').then( function(){
            defer.resolve();
        });
    }

    angular.forEach( $scope.testArray, function(value){
        promises.push(writeSome(value));
    });

    $q.all(promises).then(lastTask);

    return defer.promise;
}

使用新的ES7,您可以以更简单的方式获得相同的结果:

let promises =  angular.forEach( $scope.testArray, function(value){
    writeSome(value);
});

let results = await Promise.all(promises);

console.log(results);

您可以同时使用
$q
和“reduce”来链接承诺

function setAutoJoin() {
    var deferred = $q.defer(), data;
    var array = _.map(data, function(g){
            return g.id;
        });

    function waitTillAllCalls(arr) {
        return arr.reduce(function(deferred, email) {
            return somePromisingFnWhichReturnsDeferredPromise(email);
        }, deferred.resolve('done'));
    }

    waitTillAllCalls(array);

    return deferred.promise;
}

这对我使用ES5语法很有效

function outerFunction(bookings) {

    var allDeferred = $q.defer();
    var promises = [];

    lodash.map(bookings, function(booking) {
        var deferred = $q.defer();

        var query = {
            _id: booking.product[0].id,
            populate: true
        }

        Stamplay.Object("product").get(query)
        .then(function(res) {
            booking.product[0] = res.data[0];
            deferred.resolve(booking)
        })
        .catch(function(err) {
            console.error(err);
            deferred.reject(err);
        });

        promises.push(deferred.promise);
    });

    $q.all(promises)
    .then(function(results) { allDeferred.resolve(results) })
    .catch(function(err) { allDeferred.reject(results) });

    return allDeferred.promise;
}

(1) 关于从循环内部调用的函数:它们必须按顺序运行还是并行运行,在所有函数完成后仍需要运行最后一个块?并且:(2)如果其中一个函数导致错误,该怎么办?如果您使用的是写函数,这些函数通常也是异步的,所以很有可能一切都“按预期”工作;也就是说,angular开始了所有的写操作(这只需要一小部分时间),但是写操作本身需要很长时间。你在写什么,你在使用什么API?@NikosParaskevopoulos(1)我真的不在乎它们是并行运行还是顺序运行,它们可以并行运行,因为它们互不依赖。现在,每个内部函数返回一个承诺,并在操作结束时解析,这意味着它们以串行方式执行。明白了,最后一个操作必须始终是执行的最后一个操作,不管前一个操作是并行运行还是串行运行。(2) 好问题,我想可能会记录一些警告,但这并不重要。@Hylianpuffball我正在为文件编写一个JSONObject,我使用chromes的文件系统进行存储。我想最重要的部分是,我在fileWriter.onwriteend、fileWriter.onerror等中解析延迟。出于兴趣,Angualr是否提供了要分离的
$q.defer().resolve()
,如jQuery?换句话说,您是否可以编写
writeSome('finish')。然后(defer.resolve)?如果是这样的话,代码会稍微紧凑一些,但在其他方面是相同的。建议不错。“then”函数接受一个函数,该函数将在解析承诺时被调用,因此,如果传递参数defer.resolve,则“yes”将起作用。我将保留现在的答案,因为这个问题也有一些登录(为了清楚起见,我省略了)。谢谢你的建议@grufbunny,我会尽快调查并让你知道@谢谢你的解释!承诺。推。。。而$q.正是我想要的@Jason,把承诺串起来:。你确定
angular.forEach()
就是这样工作的吗?will
let promises=$scope.testArray.map(writeSome)不是更好吗?并且
让结果=等待承诺.all($scope.testArray.map(writeSome))更紧凑。@Roamer-1888如果不起作用,请随意编辑。我想你是对的,我还没有完全测试我在C#中看到的等待。我想他们都有相同的想法。
function outerFunction(bookings) {

    var allDeferred = $q.defer();
    var promises = [];

    lodash.map(bookings, function(booking) {
        var deferred = $q.defer();

        var query = {
            _id: booking.product[0].id,
            populate: true
        }

        Stamplay.Object("product").get(query)
        .then(function(res) {
            booking.product[0] = res.data[0];
            deferred.resolve(booking)
        })
        .catch(function(err) {
            console.error(err);
            deferred.reject(err);
        });

        promises.push(deferred.promise);
    });

    $q.all(promises)
    .then(function(results) { allDeferred.resolve(results) })
    .catch(function(err) { allDeferred.reject(results) });

    return allDeferred.promise;
}