Par*_*ord 2 javascript foreach try-catch async-await
我有一个类似数组的结构,它公开异步方法。异步方法调用包含 try-catch 块,这些块反过来在捕获错误的情况下公开更多异步方法。我想了解为什么forEach不能很好地使用async/ await。
let items = ['foo', 'bar', 'baz'];
// Desirable behavior
processForLoop(items);
/* Processing foo
* Resolved foo after 3 seconds.
* Processing bar
* Resolved bar after 3 seconds.
* Processing baz
* Resolved baz after 3 seconds.
*/
// Undesirable behavior
processForEach(items);
/* Processing foo
* Processing bar
* Processing baz
* Resolved foo after 3 seconds.
* Resolved bar after 3 seconds.
* Resolved baz after 3 seconds.
*/
async function processForLoop(items) {
for(let i = 0; i < items.length; i++) {
await tryToProcess(items[i]);
}
}
async function processForEach(items) {
items.forEach(await tryToProcess);
}
async function tryToProcess(item) {
try {
await process(item);
} catch(error) {
await resolveAfter3Seconds(item);
}
}
// Asynchronous method
// Automatic failure for the sake of argument
function process(item) {
console.log(`Processing ${item}`);
return new Promise((resolve, reject) =>
setTimeout(() => reject(Error('process error message')), 1)
);
}
// Asynchrounous method
function resolveAfter3Seconds(x) {
return new Promise(resolve => setTimeout(() => {
console.log(`Resolved ${x} after 3 seconds.`);
resolve(x);
}, 3000));
}
Run Code Online (Sandbox Code Playgroud)
jib*_*jib 10
我想了解为什么
forEach不能很好地使用async/await。
当我们认为这async只是返回承诺的函数的语法糖时,这会更容易。
项目。forEach (f) 需要一个函数f作为参数,它在返回之前一次对每个项目执行一次。它忽略 的返回值f。
items.forEach(await tryToProcess) 废话相当于 Promise.resolve(tryToProcess).then(ttp => items.forEach(ttp))
和功能上没有什么不同items.forEach(tryToProcess)。
现在tryToProcess返回一个承诺,但forEach忽略返回值,正如我们所提到的,所以它忽略了那个承诺。这是个坏消息,可能会导致未处理的拒绝错误,因为所有承诺链都应该返回或终止以catch正确处理错误。
这个错误就相当于忘记了await。不幸的是,没有array.forEachAwait()。
项目。map (f) 稍微好一点,因为它从 的返回值中创建了一个数组f,在这种情况下,它tryToProcess会给我们一个承诺数组。例如,我们可以这样做:
await Promise.all(items.map(tryToProcess));
Run Code Online (Sandbox Code Playgroud)
...但tryToProcess对每个项目的所有调用将彼此并行执行。
重要的是,map并行运行它们。Promise.all只是等待它们完成的一种手段。
我总是在函数中使用for of而不是:forEachasync
for (item of items) {
await tryToProcess(item);
}
Run Code Online (Sandbox Code Playgroud)
...即使await在循环中没有,以防万一我以后添加一个,以避免这个脚枪。
没有办法像那样使用forEachwith -不能串行运行异步迭代,只能并行运行(即使这样,with会更好)。相反,如果您想使用数组方法,请使用上一次迭代的 Promise 的分辨率:awaitforEachmapPromise.allreduceawait
let items = ['foo', 'bar', 'baz'];
processForEach(items);
async function processForLoop(items) {
for (let i = 0; i < items.length; i++) {
await tryToProcess(items[i]);
}
}
async function processForEach(items) {
await items.reduce(async(lastPromise, item) => {
await lastPromise;
await tryToProcess(item);
}, Promise.resolve());
}
async function tryToProcess(item) {
try {
await process(item);
} catch (error) {
await resolveAfter3Seconds(item);
}
}
// Asynchronous method
// Automatic failure for the sake of argument
function process(item) {
console.log(`Processing ${item}`);
return new Promise((resolve, reject) =>
setTimeout(() => reject(Error('process error message')), 1)
);
}
// Asynchrounous method
function resolveAfter3Seconds(x) {
return new Promise(resolve => setTimeout(() => {
console.log(`Resolved ${x} after 3 seconds.`);
resolve(x);
}, 3000));
}Run Code Online (Sandbox Code Playgroud)
另请注意,如果函数中的 onlyawait正好在函数返回之前,那么您也可以只返回 Promise 本身,而不是让函数为async。
| 归档时间: |
|
| 查看次数: |
4429 次 |
| 最近记录: |