等待所有嵌套的promises完成,但仍然对每个单独的解析做出反应

时间:2017-10-31 12:39:31

标签: javascript promise es6-promise

假设newsService.getNews()返回一个应该解析为某个服务返回的随机新闻条目的promise,而translateService.translate()返回一个应该解析为传递文本转换的promise。

var newsPromises = [];
var translatePromises = [];
for (var i = 0; i < 5; i++) {
    var p1 = this.newsService.getNews();
    newsPromises.push(p1);

    p1.then(function (data) {
        var p2 = this.translateService.translate(data);
        translatePromises.push(p2);
        p2.then(function (translatedData) {
            addNews(`${data} (${translatedData})`);

        }, function (fail) {
            console.log(fail.message);
        });

    }, function (fail) {
        console.log(fail.message);
    });
}

现在页面最初显示了一个加载微调器,当所有promise(包括嵌套转换promise)完成(成功或失败)时,我想隐藏它:

   Promise.all(newsPromises)
        .then(function (results) {
            Promise.all(translatePromises).then(function (results) {
                    removeLoading();
                },
                function (err) {
                    removeLoading();
                }
            );

        }, function (err) {
            Promise.all(translatePromises).then(function (results) {
                    removeLoading();
                },
                function (err) {
                    removeLoading();
                }
            );
        });

这段代码a)不能正常工作,因为加载微调器有时会在promises解决之前消失,而b)非常复杂。

这是如何正确完成的? (与香草JS / ES6)

2 个答案:

答案 0 :(得分:1)

请记住,promises链是管道,当结果通过处理程序时,每个处理程序都可以转换链的结果。见评论:

// We only need one array of promises
const promises = [];
// Build the array
for (let i = 0; i < 5; i++) {
    // Add this promise to the array
    promises.push(
        // Get the news...
        this.newsService.getNews().then(
            // ...and translate it...
            data => this.translateService.translate(data)
                .then(translatedData => {
                    // ...and show it as soon as it's available
                    addNews(`${data} (${translatedData})`);
                    // Note that here we're converting the resolution value to
                    // `undefined`, but nothing uses it so...
                    // If you want something to be able to use it,
                    // return `translatedData` (or `data` or...)
                })
        )
        .catch(fail => {
            console.log(fail.message);
            // WARNING: Here you're converting rejection to resolution with `undefined`
        })
    );
}
// Wait until all that is done before removing the loading indicator
Promise.all(promises).then(removeLoading);

请注意,我们在catch承诺上不需要Promise.all的唯一原因是您忽略了(除了记录)发生的错误,因此我们知道承诺永远不会拒绝

另请注意,上述假设removeLoading不会关注它收到的参数,并且它不会返回可能拒绝的承诺。如果它关心参数并且在没有参数的情况下调用它很重要,请将Promise.all位更改为:

Promise.all(promises).then(() => removeLoading());

如果它返回可能拒绝的承诺,您还需要一个catch处理程序。

答案 1 :(得分:0)

在这种情况下我创建了全局计数器loadersCount = 0

每次致电this.newsService.getNews()来电函数loaderStart()

每次致电addNews()console.log(fail.message)致电loaderStop()

function loaderStart () {
  if (loadersCount === 0) {
    addLoading();
  }
  loadersCount++;
}

function loaderStop () {
  if (loadersCount === 1) {
    removeLoading();
  }
  loadersCount--;
}