【发布时间】:2020-12-22 22:34:33
【问题描述】:
我正在为我的问题寻找 ES6 解决方案(我想这可能很常见......):
我有一个远程提供商列表,每个提供商在一个页面上发布一个项目列表,每个项目的详细信息在其他页面上。 我需要从所有提供商那里获取所有项目的详细信息,每小时一次(比如说)。
我想并行获取所有提供者列表,并且在解决每个列表后立即从该列表中并行获取所有项目详细信息(我将根据需要限制请求以避免ECONNRESET 错误,但这是另一个故事)。
这是我的暂定解决方案的实现:
const providers = [
{
name: 'A',
urlList: 'https://jsonplaceholder.typicode.com/users/?_start=0&_limit=1',
urlItem: 'https://jsonplaceholder.typicode.com/posts?userId=%id%&_start=0&_limit=2',
},
{
name: 'B',
urlList: 'https://jsonplaceholder.typicode.com/users/?_start=2&_limit=2',
urlItem: 'https://jsonplaceholder.typicode.com/posts?userId=%id%&_start=0&_limit=2',
},
{
name: 'C',
urlList: 'https://jsonplaceholder.typicode.com/users/?_start=4&_limit=2',
urlItem: 'https://jsonplaceholder.typicode.com/posts?userId=%id%&_start=0&_limit=2',
},
];
const getList = (provider) => fetch(provider.urlList).then(res => res.json());
const getItems = (provider, list) => Promise.all(
list.map(item => {
return fetch(provider.urlItem.replace("%id%", item.id)).then(res => res.json()).then(res => res.map(r => ({ provider: provider.name, name: item.name, ...r })));
})
);
const providerFetch = async provider => {
console.log(`providerFetch ${provider.name} start`);
try {
const list = await getList(provider);
const items = await getItems(provider, list);
return items;
} catch (error) {
console.error(`providerFetch ${provider.name} error: ${error}`);
} finally {
console.log(`providerFetch ${provider.name} done`);
}
}
(async () => {
console.log('start');
const data = await Promise.all(
providers.map(async provider => {
const providerData = providerFetch(provider);
return providerData;
})
);
//console.dir(data, { depth: 3 });
console.log(data.flat(2));
console.log('end');
})();
它至少有两个问题:
- 我使用
Promise.all()两次,所以我得到一个3 维数组,而我更喜欢一个简单的一维数组...有没有办法让Promise.all()连接承诺结果而不是推送它们? - 最严重的问题:我正在获取所有供应商列表,并且只有在所有供应商都准备好后,我才开始获取项目(按预期并行)。相反,我想在获取列表后立即开始为每个列表获取项目。你能给我一些提示如何改变我的代码来实现它吗?
更新: 还要感谢@Bergi 的 cmets,我可以理解:
- 第 1 点:这可以通过在最终数据上使用
flat(2)(2 是要展平的深度)简单地解决;该解决方案不是那么圆滑,但看起来promise.All()只能推送,不能连接。我确实更改了我的代码示例以显示它。 - 第 2 点:
providerFetch连续工作的事实只是我的一个假设,可能是因为getLists 在这个测试代码中是如此之快......事实上,添加了延迟在getList返回之前,我可以看到一些getItems在所有getLists完成之前开始。
【问题讨论】:
-
"我正在获取所有供应商列表,并且只有在所有供应商都准备好后,我才开始获取项目" - 嗯,不,你没有。您的
providerFetch在getList完成后立即调用getItems。您的代码中没有任何内容等待所有列表。 -
"我使用了两次
Promise.all(),所以我得到了一个 3 维数组" - 嵌套两个Promise.alls 可以得到一个二维数组。第三维来自getItems获取数组。 -
"有没有办法让
Promise.all()concat 承诺结果" - 不,没有,但是在Promise.all()承诺履行后展平嵌套数组很简单(在.then回调或await之后)。
标签: javascript node.js asynchronous ecmascript-6 es6-promise