В вашем первом кодовом блоке (который, как вы сказали, работает, но последовательно) вы звоните ProcessService.getData
, но во втором вы звоните RSSService.getRssAsync
.
Если я предполагаю, что вы намеревались использовать ProcessService.getData
и что он возвращает обещание (что, как я полагаю, должно произойти, вы сказали, что ваш первый блок кода работает, как и ожидалось), то для параллельной подачи каналов вы должны что-то сделать как ваш второй кодовый блок, но он не должен быть таким сложным:
for (const source of sources) {
await Promise.all(source.feeds.map(feed => ProcessService.getData(feed, source)));
}
console.log('Done processing.');
Поскольку ProcessService.getData
возвращает обещание, а то, что нам нужно для Promise.all
, является массивом обещаний, мы не выполняем обратный вызов async
, мы просто используем обещание, которое 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;
}
Если вам действительно нужно использовать RSSService.getRssAsync
, может показаться, что он не возвращает обещание, поскольку, если бы он это сделал, ваш код работал бы так, как ожидалось (даже если он мог бы быть проще). Чтобы преобразовать API обратного вызова в API обещаний, см. ответы на этот вопрос .
Ваша функция getData
имеет несколько проблем:
- Поскольку вы явно создаете обещание, оно не должно быть функцией
async
. Вы используете функцию async
, когда хотите использовать await
для существующего обещания. Если вы создаете новое обещание, вам почти никогда не понадобится функция async
.
- Функция, которую вы передаете в
new Promise
(функция исполнения обещания ) должна никогда быть async
.
- Вы показываете, что звоните
resolve()
без аргументов. Это нормально, если вы действительно хотите выполнить обещание со значением undefined
(для которого есть несколько случаев ограниченного использования), но если функция называется getData
, она действительно должна возвращать данные, а не undefined
.
Итак:
getData: function(data, source) {
// ^---- no `async` here
return new Promise((resolve, reject) => {
// ^---- no `async` here
try {
...
resolve(/*...should have data here...*/)
} catch(e) {
reject(e)
}
})
}
Также обратите внимание, что вы можете использовать синтаксис метода (похоже, он находится в инициализаторе объекта):
getData(data, source) {
// ^
return new Promise((resolve, reject) => {
try {
...
resolve(/*...should have data here...*/)
} catch(e) {
reject(e)
}
})
}