Es scheint einige Probleme zu geben, die async / await mit .reduce () beinhalten, wie zum Beispiel:
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)
Das data
Objekt wird protokolliert, bevor der Vorgang this.store
abgeschlossen ist ...
Ich weiß, dass Sie Promise.all
mit asynchronen Schleifen verwenden können, aber gilt das für .reduce()
?
javascript
promise
async-await
reduce
ecmascript-next
benhowdle89
quelle
quelle
initialValue
von demreduce
braucht keine seinPromise
, es wird jedoch in den meisten Fällen klärt die Absicht.await
es wirklich nicht , einen einfachen Wert in ein Versprechennull
nicht wahr?Ich mag Bergis Antwort, ich denke, es ist der richtige Weg.
Ich möchte auch eine meiner Bibliotheken namens Awaity.js erwähnen
Was können Sie mühelos Funktionen wie
reduce
,map
undfilter
mitasync / 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: { ... } }
quelle
Sie können Ihre gesamte Map / Reduce-Iterator-Blöcke in ihre eigene Promise.resolve einbinden und darauf warten, dass diese abgeschlossen ist. Das Problem ist jedoch, dass der Akkumulator nicht die resultierenden Daten / Objekte enthält, die Sie bei jeder Iteration erwarten würden. Aufgrund der internen Kette async / await / Promise handelt es sich bei dem Akkumulator um tatsächliche Promises selbst, die sich wahrscheinlich noch nicht aufgelöst haben, obwohl Sie vor Ihrem Aufruf des Geschäfts ein Schlüsselwort await verwendet haben (was möglicherweise zu der Annahme führt, dass die Iteration nicht tatsächlich erfolgt kehren Sie zurück, bis dieser Aufruf abgeschlossen ist und der Akku aktualisiert wurde.
Dies ist zwar nicht die eleganteste Lösung, Sie haben jedoch die Möglichkeit, Ihre Datenobjektvariable aus dem Gültigkeitsbereich zu verschieben und als Let zuzuweisen, damit eine ordnungsgemäße Bindung und Mutation erfolgen kann. Aktualisieren Sie dann dieses Datenobjekt in Ihrem Iterator, wenn die Aufrufe asynchron / warten / versprechen aufgelöst werden.
/* allow the result object to be initialized outside of scope rather than trying to spread results into your accumulator on iterations, else your results will not be maintained as expected within the internal async/await/Promise chain. */ let data = {}; await Promise.resolve(bodies.reduce(async(accum, current, index) => { const methodName = methods[index] const method = this[methodName]; if (methodName == 'foo') { // note: this extra Promise.resolve may not be entirely necessary const cover = await Promise.resolve(this.store(current.cover, id)); current.cover = cover; console.log(current); data = { ...data, ...current, }; return data; } data = { ...data, ...method(current.data) }; return data; }, {}); console.log(data);
quelle
export const addMultiTextData = async(data) => { const textData = await data.reduce(async(a, { currentObject, selectedValue }) => { const { error, errorMessage } = await validate(selectedValue, currentObject); return { ...await a, [currentObject.id]: { text: selectedValue, error, errorMessage } }; }, {}); };
quelle
[OPs nicht genau ansprechen; konzentrierte sich auf andere, die hier landen.]
Reduzieren wird häufig verwendet, wenn Sie das Ergebnis der vorherigen Schritte benötigen, bevor Sie das nächste verarbeiten können. In diesem Fall können Sie Versprechen a la aneinander reihen:
promise = elts.reduce( async (promise, elt) => { return promise.then(async last => { return await f(last, elt) }) }, Promise.resolve(0)) // or "" or [] or ...
Hier ist ein Beispiel mit fs.promise.mkdir () (sicher, viel einfacher, mkdirSync zu verwenden, aber in meinem Fall ist es über ein Netzwerk):
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')
Unten ist ein weiteres Beispiel, das 100 + 200 ... 500 addiert und ein bisschen wartet:
async function slowCounter () { const ret = await ([100, 200, 300, 400, 500]).reduce( async (promise, wait, idx) => { return promise.then(async last => { const ret = last + wait console.log(`${idx}: waiting ${wait}ms to return ${ret}`) await new Promise((res, rej) => setTimeout(res, wait)) return ret }) }, Promise.resolve(0)) console.log(ret) } slowCounter ()
quelle
So reduzieren Sie Async:
async function asyncReduce(arr, fn, initialValue) { let temp = initialValue; for (let idx = 0; idx < arr.length; idx += 1) { const cur = arr[idx]; temp = await fn(temp, cur, idx); } return temp; }
quelle