【问题标题】:How can I return an array of Promises from a then clause如何从 then 子句返回 Promise 数组
【发布时间】:2016-11-03 15:05:05
【问题描述】:

我看到了一个类似的问题here,它没有解决我的问题。我试图每 10 小时运行一次 cron 作业,让我首先获取类别,然后根据类别,我找到每个类别的信息。我怎样才能简化下面的承诺。我没有使用 Bluebird 或 Q,这是原生 JS 的承诺。老实说,下面的代码看起来就像 Promise 应该避免的回调地狱,任何建议

flipkart.getAllOffers = function () {
    interval(43200, () => {
        flipkart.findAllCategories()
            .then((categories) => {
                flipkart.save('flipkart_categories.json', categories)
                if (categories) {
                    for (let item of categories) {
                        flipkart.findAllForCategory(item.category, item.top)
                            .then((items) => {
                                flipkart.save('flipkart_top_' + item.category + '.json', items)
                            }).catch((error) => {
                                console.log(error)
                            })
                    }
                }
            })
            .catch((error) => {
                console.log(error)
            })
    })
}

function interval(seconds, callback) {
    callback();
    return setInterval(callback, seconds * 1000);
}

【问题讨论】:

  • 首先,您使用的缩进比需要的多。通过将.then() 处理程序置于另一个缩进级别,您累积的缩进量比需要的多得多。这是个人风格的事情,但不是必需的,并且会创建比简单阅读代码所需的更多的缩进。

标签: promise es6-promise


【解决方案1】:

如果您停止为 .then() 使用额外的缩进级别,那么您的结构非常简单。

一个 .then() 处理程序包含 if() 声明 包含一个 for 循环 包含另一个异步操作

在这个修改后的版本中,一半的缩进来自你的iffor,这与promise 无关。其余的对我来说似乎很合乎逻辑,根本不像回调地狱。这是实现您展示的逻辑所必需的。

flipkart.getAllOffers = function () {
    interval(43200, () => {
        flipkart.findAllCategories().then((categories) => {
            flipkart.save('flipkart_categories.json', categories)
            if (categories) {
                for (let item of categories) {
                    flipkart.findAllForCategory(item.category, item.top).then((items) => {
                        flipkart.save('flipkart_top_' + item.category + '.json', items)
                    }).catch((error) => {
                        console.log(error)
                        throw error;     // don't eat error, rethrow it after logging
                    });
                }
            }
        }).catch((error) => {
            console.log(error)
        })
    })
}

如果flipkart.save() 也是异步的并返回一个promise,那么您可能也希望将它们挂钩到promise 链中。


您始终可以创建一个可以改善外观的辅助函数,如下所示:

flipkart.getAllOffers = function () {
    interval(43200, () => {
        flipkart.findAllCategories().then(iterateCategories).catch((error) => {
            console.log(error);
        })
    })
}

function iterateCategories(categories) {
    flipkart.save('flipkart_categories.json', categories);
    if (categories) {
        for (let item of categories) {
            flipkart.findAllForCategory(item.category, item.top).then((items) => {
                flipkart.save('flipkart_top_' + item.category + '.json', items);
            }).catch((error) => {
                console.log(error);
            });
        }
    }    
}

如果您尝试收集所有结果(您的标题暗示了这一点,但您的问题实际上并未提及),那么您可以这样做:

flipkart.getAllOffers = function () {
    interval(43200, () => {
        flipkart.findAllCategories().then(iterateCategories).then((results) => {
            // all results here
        }).catch((error) => {
            console.log(error);
        });
    })
}

function iterateCategories(categories) {
    flipkart.save('flipkart_categories.json', categories);
    let promises = [];
    if (categories) {
        for (let item of categories) {
            let p = flipkart.findAllForCategory(item.category, item.top).then((items) => {
                flipkart.save('flipkart_top_' + item.category + '.json', items);
            }).catch((error) => {
                console.log(error);
            });
            promises.push(p);
        }
    }
    // return promise here that collects all the other promises
    return Promise.all(promises);
}

【讨论】:

  • 添加了几个版本以显示不同的编码风格并显示收集所有结果。
  • 非常感谢您的所有建议,我将无法使用 Promise.all,因为如果 url 过期并且 Promise.any 有时会在不检查是否全部完成的情况下解决,其中一些可能会失败,承诺。从蓝鸟定居似乎并不存在于原生 es6 承诺中:)
  • @PirateApp - 最后两个代码块的工作方式,任何承诺拒绝都会被捕获并在它到达Promise.all()之前处理,所以这不是问题。如果你有一个.catch() 处理程序并且你没有返回一个被拒绝的承诺或从其中抛出,那么被拒绝的承诺被认为是“已处理”并且状态更改为已解决。由于最后两个都有内部的.catch() 记录它并且它们不会重新抛出,Promise.all() 只会看到已解决的承诺。你应该没事。
猜你喜欢
  • 2021-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-14
  • 2018-09-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多