オブジェクトの配列をフィルタリングしようとしています。フィルタリングする前に、それらを何らかの形式に変換する必要があり、この操作は非同期です。
const convert = () => new Promise( resolve => {
setTimeout( resolve, 1000 );
});
そのため、私の最初の試みは、async/awaitを使用して次のようなことをすることでした。
const objs = [ { id: 1, data: "hello" }, { id: 2, data: "world"} ];
objs.filter( async ( obj ) => {
await convert();
return obj.data === "hello";
});
皆さんご存知かもしれませんが、Array.protoype.filter
は、コールバックがtrueまたはfalseを返す必要がある関数です。 filter
は同期です。前の例では、どれも返さず、Promiseを返します(すべての非同期関数はPromisesです)。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
推測できるように、前のコードは実際には機能しません...その仮定は正しいです。
非同期関数でフィルターを機能させるために、私はstackoverflowをチェックし、このトピックを見つけました:
残念ながら、選択された答えは非常に複雑であり、クラスを使用しています。これは私には役に立たないでしょう。その代わりに、機能的なアプローチで単純な関数を使用する、より単純なソリューションを探しています。
最後に1つの解決策があります。コールバック付きのマップを使用してフィルターをシミュレートします。
https://stackoverflow.com/a/46842181/1337392
しかし、フィルター関数を置き換えるのではなく、修正したいと考えていました。
非同期関数でフィルターを使用する方法はありません(少なくとも私が知っていること)。 promiseのコレクションでfilterを使用する最も簡単な方法は、Promise.all
を使用してから、結果のコレクションに関数を適用することです。次のようになります。
const results = await Promise.all(your_promises)
const filtered_results = results.filter(res => //do your filtering here)
それが役に立てば幸い。
Scramjet fromArray/toArrayメソッドを使用...
const result = await scramjet.fromArray(arr)
.filter(async (item) => somePromiseReturningMethod(item))
.toArray();
それと同じくらい簡単です-コピー/貼り付けの準備ができた例です:
const scramjet = require('../../');
async function myAsyncFilterFunc(data) {
return new Promise(res => {
process.nextTick(res.bind(null, data % 2));
});
}
async function x() {
const x = await scramjet.fromArray([1,2,3,4,5])
.filter(async (item) => myAsyncFilterFunc(item))
.toArray();
return x;
}
x().then(
(out) => console.log(out),
(err) => (console.error(err), process.exit(3)) // eslint-disable-line
);
Disclamer:私はscramjetの著者です。 :)
フィルターを呼び出す配列に並列配列を作成します。私の例では、isValid
で、フィルターfuncからのすべての約束を待ちます。 filter
のコールバックで、2番目の引数indexを使用して、並列配列にインデックスを付け、フィルター処理する必要があるかどうかを判断します。
// ===============================================
// common
// ===============================================
const isValid = async () => Math.random() > 0.5;
const values = Array(100).fill(42); // array of size 100 with all its values being 42
// ===============================================
// won't filter anything
// ===============================================
const filtered = values.filter(async v => await isValid());
console.log(filtered.length);
// ===============================================
// filters
// ===============================================
(async () => {
const shouldFilter = await Promise.all(values.map(isValid));
const filtered2 = values.filter((value, index) => shouldFilter[index]);
console.log(filtered2.length);
})();
Promise
インスタンスには真の値があるため、この動作は理にかなっていますが、一目では直観的ではありません。