如何使用异步代码在forEach循环上进行promise / callback

时间:2015-09-29 15:21:05

标签: javascript asynchronous promise

我认为我正在寻找承诺,但我不知道如何在我的案例中使用它。
我只想在完成所有异步代码时console.log('ended')。我有一个DZ.api的回调但不是forEach()的回调,这样做的最佳方式是什么? / p>

    _.forEach(filteredTracks, function(n) {
        DZ.api('/playlist/'+ n.id +'/tracks', function(response) {
            _.forEach(response.data, function(n) {
                SP.api('/search/'+n.title, function(response) {
                    console.log(response);
                });
            });
        });
    });
    console.log('ended');

3 个答案:

答案 0 :(得分:4)

您正在寻找Promise.all - > Promise.all(arrayOfPromise).then(function (result) {})

使用您当前的代码,如果SP.api已经与Promise兼容,请执行以下操作:

_.map(filteredTracks, function(n) {
    return DZ.api('/playlist/'+ n.id +'/tracks')
            .then(function (response) {
                _.map(response.data, function(n) {
                    return SP.api('/search/'+n.title);
                });

                return Promises.all(response.data);
            });
    });
});

Promise.all(filteredTracks)
    .then(function (results) {
        console.log('ended');
    });

如果SP.api和DZ Api未返回承诺,您可以:

Promisify SP.api DZ Api并使用我之前编写的相同代码

或者在._map

中返回promises
_.map(filteredTracks, function(n) {
    var promise = new Promise(function (resolve, reject) {
        DZ.api('/playlist/'+ n.id +'/tracks', function (response) {
                _.map(response.data, function(n) {
                    var insidePromise = new Promise(function (resolve, reject) {
                        return SP.api('/search/'+n.title, function (result) {
                            resolve(result);
                        });
                    })

                    return insidePromise;
                });

                resolve(Promises.all(response.data));
            });
        });
    });

    return promise;
});

Promise.all(filteredTracks).then(function (results) {
        console.log('ended');
    });

答案 1 :(得分:2)

你想要的是用forEach替换map并让每个调用返回一个Promise,连接内循环的结果,因为你有两个级别。然后将Promises数组传递给Promise.all(),这会创建一个Promise,当数组中的所有Promise都已解析时,它会解析。为此,您必须重构代码以从DZ.api函数返回Promises而不是使用回调。简而言之:

let promises = filteredTracks.map(track => {
    return DZ.promisedApi(track).then(response => {
        return Promise.all(response.data.map(n => SP.promisedApi(n))
    }) 
})

Promise.all(promises).then(() => console.log("done!"))

答案 2 :(得分:1)

您没有指定您正在使用的库,但总体而言我建议您将所有API调用的承诺保存到数组中,然后使用Promises.all()

所以你会有类似的东西(警告:未经测试的代码,仅供参考):

var promisesArray = []

_.forEach(filteredTracks, function(n) {
    DZ.api('/playlist/'+ n.id +'/tracks', function(response) {
        _.forEach(response.data, function(n) {
            promisesArray.push( SP.api('/search/'+n.title, function(response) {
                console.log(response);
            }));
        });
    });
});

Promise.all(promisesArray)
        .then(function(value){
          console.log('ended');
        })

基本上,正如Promise reference page所述,Promise.all创建了一个新的Promise,当所有作为参数传递的promise被解析时,它将被解析。在我看来,这与您的用例相符。