以下のように、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)
_
data
オブジェクトが記録されますbefore the _this.store
_ completes ...
非同期ループで_Promise.all
_を利用できることは知っていますが、それは.reduce()
にも当てはまりますか?
問題は、アキュムレーターの値が約束であるということです-それらはasync function
sの戻り値です。逐次評価(および最後の反復を除くすべて)を取得するには、以下を使用する必要があります。
const data = await array.reduce(async (accumP, current, index) => {
const accum = await accumP;
…
}, Promise.resolve(…));
とは言っても、async
/await
の場合、一般的に 配列反復メソッドの代わりにプレーンループを使用する をお勧めします。
私はベルギの答えが好きです、それは正しい道だと思います。
私は Awaity.js と呼ばれる私のライブラリにも言及したいと思います
これにより、async / await
でreduce
、map
、_filter
などの関数を簡単に使用できます。
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: { ... } }
Map/reduceイテレータブロック全体を独自のPromise.resolveにラップし、完了するのを待つことができます。ただし、問題は、アキュムレータに各反復で予想される結果のデータ/オブジェクトが含まれていないことです。内部async/await/Promiseチェーンにより、アキュムレーターは、ストアへの呼び出しの前にawaitキーワードを使用しているにもかかわらず、まだ解決されていない実際のPromiseそのものになります(これにより、反復が実際には行われないと思われる可能性があります)その呼び出しが完了し、アキュムレーターが更新されるまで戻ります。
これは最もエレガントな解決策ではありませんが、あなたが持っている1つのオプションは、適切なバインディングと突然変異ができるように、スコープ外にdataオブジェクト変数を移動し、それをletとして割り当てることです発生する。次に、async/await/Promise呼び出しが解決するときに、イテレーター内からこのデータオブジェクトを更新します。
/* 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);
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
}
};
}, {});
};