es6在for-of循环中嵌套了并行循环

时间:2019-05-25 16:10:34

标签: javascript for-loop ecmascript-6

所以我有一个带有嵌套数组(sources.feed)的数组(sources),sources应该串联运行(一个接一个),sources.feed应该并行运行。

我已经实现了同时运行它们:

 for (const source of sources) {
     for (const feed of source.feeds) {
         await ProcessService.getData(feed, source)
     }
   }
console.log('Done processing.') //Triggers at the end (as expected)

这是我几次尝试的最后一次:

for (const source of sources) {
   await Promise.all(source.feeds.map(async (feed) => {
      await ProcessService.getData(feed, source)
   }))
}
console.log('Done processing.') //Triggers before it is done

为清楚起见已更新(只能调用ProcessService.getData())

getData: async function(data, source) {
    return new Promise(async (resolve, reject) => {
      try {
          ...
          resolve()
      } catch(e) {
          reject(e)
      }
   })
 }

2 个答案:

答案 0 :(得分:4)

在您的第一个代码块中(您说的有效,但是连续),您正在调用ProcessService.getData,而在第二个代码块中,您正在调用RSSService.getRssAsync

如果我假设您打算使用ProcessService.getData并且它返回一个promise(我认为必须这样做,那么您说您的第一个代码块可以按预期工作),然后使提要并行类似于 的第二个代码块,但不必太复杂:

for (const source of sources) {
    await Promise.all(source.feeds.map(feed => ProcessService.getData(feed, source)));
}
console.log('Done processing.');

由于ProcessService.getData返回了一个promise,而我们想要的Promise.all是一个promise数组,因此我们不进行回调async,我们只使用promise {{1 }}给了我们。

依次遍历各个源,获取(并行)第一个源的所有提要,然后获取(并行)下一个源的所有提要,等等。

实时示例:

ProcessService.getData
(async () => {
    const ProcessService = {
        getData(data, source) {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    try {
                        console.log(`Done with feed ${source.name} ${data}`);
                        resolve(/*...should have data here...*/)
                    } catch(e) {
                        reject(e)
                    }
                }, Math.random() * 500);
            });
        }
    }

    const sources = [
        {name: "Source 1", feeds: ["11", "12", "13"]},
        {name: "Source 2", feeds: ["21", "22", "23"]},
        {name: "Source 3", feeds: ["31", "32", "33"]},
        {name: "Source 4", feeds: ["41", "42", "43"]}
    ];

    for (const source of sources) {
        console.log(`Processing ${source.name}`);
        await Promise.all(source.feeds.map(feed => ProcessService.getData(feed, source)));
    }
    console.log('Done processing.');
})().catch(e => {
    console.error(`Error: ${e.message}`);
});


如果您确实需要使用.as-console-wrapper { max-height: 100% !important; },则它似乎不会返回承诺,因为即使这样做,您的代码也可以按预期工作(即使可能更简单)。要将回调API转换为Promise API,请参见this question's answers


您的RSSService.getRssAsync函数有两个问题:

  1. 由于您正在显式创建一个Promise,因此它不应该是getData函数。当您要在现有承诺中使用async时,可以使用async功能。如果您要创建新的承诺,则几乎不需要使用await函数。
  2. 您传递给async的函数(承诺执行器函数)应该永远不为new Promise
  3. 您显示的是不带任何参数地在呼叫async。如果您真的想用值resolve()(有一些有限的用例)履行承诺,那没关系,但是如果函数被称为undefined,它实际上应该返回数据,而不是{{ 1}}。

所以:

getData

还请注意,您可以使用方法语法(这似乎在对象初始化器中):

undefined

答案 1 :(得分:1)

您可以使用Promise.all完成此操作。

等待每个系列:

for (const source of sources) {
    const promises = [];

    for (const feed of source.feeds) {
        promises.push(ProcessService.getData(feed, source));
    }

    // Wait for the series to finish before continuing
    await Promise.all(promises);
}
console.log('Done processing.');

最后等待所有嵌套项目:

const promises = [];
for (const source of sources) {
    for (const feed of source.feeds) {
        promises.push(ProcessService.getData(feed, source));
    }
}

// Wait for all of them at the end (instead of each series)
await Promise.all(promises);
console.log('Done processing.');