ben*_*e89 43 javascript reduce promise async-await ecmascript-next
似乎有一些问题将async/await与.reduce()结合起来,如下所示:
const data = await bodies.reduce(async(accum, current, index) => {
const methodName = methods[index]
const method = this[methodName]
if (methodName == 'foo') {
current.cover = await this.store(current.cover, id)
console.log(current)
return {
...accum,
...current
}
}
return {
...accum,
...method(current.data)
}
}, {})
console.log(data)
Run Code Online (Sandbox Code Playgroud)
该data对象被记录之前的this.store完成...
我知道你可以使用Promise.all异步循环,但这适用于.reduce()?
Ber*_*rgi 77
问题是你的累加器值是promises - 它们是async functions的返回值.要获得顺序评估(除了最后一次迭代之外的所有迭代),您需要使用
const data = await array.reduce(async (accumP, current, index) => {
const accum = await accumP;
…
}, Promise.resolve(…));
Run Code Online (Sandbox Code Playgroud)
也就是说,对于async/ await我一般会建议使用普通循环而不是数组迭代方法,它们性能更高,而且通常更简单.
inw*_*sel 10
当前接受的答案建议使用Promise.all()而不是async reduce. 然而,这与 an 的行为不同,async reduce并且仅与您希望异常立即停止所有迭代的情况相关,但情况并非总是如此。
此外,在该答案的评论中,建议您应该始终等待累加器作为减速器中的第一个语句,因为否则您可能会面临未处理的承诺拒绝的风险。发帖者还说这是OP所要求的,但事实并非如此。相反,他只是想知道一切何时完成。为了知道您确实需要这样做await acc,但这可能是在减速器中的任何一点。
const reducer = async(acc, key) => {
const response = await api(item);
return {
...await acc, // <-- this would work just as well for OP
[key]: response,
}
}
const result = await ['a', 'b', 'c', 'd'].reduce(reducer, {});
console.log(result); // <-- Will be the final result
Run Code Online (Sandbox Code Playgroud)
如何安全使用asyncreduce
话虽这么说,以这种方式使用减速器确实意味着您需要保证它不会抛出,否则您将得到“未处理的承诺拒绝”。完全可以通过使用try-catch, 块catch返回累加器(可选地包含失败的 API 调用的记录)来确保这一点。
const reducer = async (acc, key) => {
try {
data = await doSlowTask(key);
return {...await acc, [key]: data};
} catch (error) {
return {...await acc, [key]: {error}};
};
}
const result = await ['a', 'b', 'c','d'].reduce(reducer, {});
Run Code Online (Sandbox Code Playgroud)
与 的区别Promise.allSettled
您可以通过使用 来接近 an 的行为async reduce(带有错误捕获)Promise.allSettled。然而,这使用起来很笨拙:如果你想减少到一个对象,你需要在它后面添加另一个同步减少。
Promise.allSettled+ 常规 的理论时间复杂度也更高reduce,尽管可能很少有用例会产生影响。async reduce可以从第一项完成的那一刻开始累积,而reduceafterPromise.allSettled会被阻塞,直到所有的承诺都得到履行。当循环大量元素时,这可能会产生影响。
const reducer = async(acc, key) => {
const response = await api(item);
return {
...await acc, // <-- this would work just as well for OP
[key]: response,
}
}
const result = await ['a', 'b', 'c', 'd'].reduce(reducer, {});
console.log(result); // <-- Will be the final result
Run Code Online (Sandbox Code Playgroud)
使用以下命令检查执行顺序Promise.allSettled:
const reducer = async (acc, key) => {
try {
data = await doSlowTask(key);
return {...await acc, [key]: data};
} catch (error) {
return {...await acc, [key]: {error}};
};
}
const result = await ['a', 'b', 'c','d'].reduce(reducer, {});
Run Code Online (Sandbox Code Playgroud)
[未解决 OP 的确切问题;专注于降落在这里的其他人。]
当您需要前面步骤的结果才能处理下一步时,通常会使用Reduce。在这种情况下,你可以将 Promise 串在一起:
promise = elts.reduce(
async (promise, elt) => {
return promise.then(async last => {
return await f(last, elt)
})
}, Promise.resolve(0)) // or "" or [] or ...
Run Code Online (Sandbox Code Playgroud)
这是一个使用 fs.promise.mkdir() 的示例(当然,使用 mkdirSync 更简单,但就我而言,它是跨网络的):
const Path = require('path')
const Fs = require('fs')
async function mkdirs (path) {
return path.split(/\//).filter(d => !!d).reduce(
async (promise, dir) => {
return promise.then(async parent => {
const ret = Path.join(parent, dir);
try {
await Fs.promises.lstat(ret)
} catch (e) {
console.log(`mkdir(${ret})`)
await Fs.promises.mkdir(ret)
}
return ret
})
}, Promise.resolve(""))
}
mkdirs('dir1/dir2/dir3')
Run Code Online (Sandbox Code Playgroud)
下面是另一个例子,添加 100 + 200 ... 500 并稍等一下:
promise = elts.reduce(
async (promise, elt) => {
return promise.then(async last => {
return await f(last, elt)
})
}, Promise.resolve(0)) // or "" or [] or ...
Run Code Online (Sandbox Code Playgroud)
我喜欢贝尔吉的回答,我认为这是正确的方法。
我还想提一下我的一个库,叫做Awaity.js
它可以让你毫不费力的使用功能,如reduce,map与filter具有async / await:
import reduce from 'awaity/reduce';
const posts = await reduce([1,2,3], async (posts, id) => {
const res = await fetch('/api/posts/' + id);
const post = await res.json();
return {
...posts,
[id]: post
};
}, {})
posts // { 1: { ... }, 2: { ... }, 3: { ... } }
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
23866 次 |
| 最近记录: |