web-dev-qa-db-ja.com

Array.mapでasync awaitを使用する

次のコードがあるとします。

var arr = [1,2,3,4,5];

var results: number[] = await arr.map(async (item): Promise<number> => {
        await callAsynchronousOperation(item);
        return item + 1;
    });

次のエラーが発生します。

TS2322:タイプ 'Promise <number> []'はタイプ 'number []'に割り当て可能ではありません。タイプ '約束' <番号>はタイプ '番号'に割り当て可能ではありません。

どうすれば修正できますか? async awaitArray.mapを連携させるにはどうすればよいですか?

116
Alon

ここでの問題は、あなたが約束ではなく約束の配列をawaitしようとしていることです。これはあなたが期待することをしません。

awaitに渡されたオブジェクトがPromiseではない場合、awaitは解決しようとするのではなく、ただちにその値をそのまま返します。そのため、ここではPromiseの代わりにawaitに(Promiseオブジェクトの)配列を渡したので、awaitによって返される値は単にPromise<number>[]型のその配列になります。

ここでする必要があるのは、mapを返す前に、それを単一のPromiseに変換するために、awaitによって返される配列に対してPromise.allを呼び出すことです。

Promise.all のMDNドキュメントによると、

Promise.all(iterable)メソッドは、iterable引数内のすべてのpromiseが解決された場合に解決するpromiseを返すか、最初に渡されたpromiseが拒否されたことを理由にrejectします。

だからあなたの場合:

var arr = [1, 2, 3, 4, 5];

var results: number[] = await Promise.all(arr.map(async (item): Promise<number> => {
    await callAsynchronousOperation(item);
    return item + 1;
}));

これはあなたがここで遭遇している特定のエラーを解決するでしょう。

267
Ajedi32

ネイティブのPromiseではなくBluebirdを使用している場合は、それに対する別の解決策があります。

Promise.map() を使用して、array.mapとPromise.allを混在させることもできます。

あなたの場合:

  var arr = [1,2,3,4,5];

  var results: number[] = await Promise.map(arr, async (item): Promise<number> => {
    await callAsynchronousOperation(item);
    return item + 1;
  });
11
Gabriel Cheung

あなたが約束の配列にマップするなら、あなたはそれから数の配列にそれらすべてを解決することができます。 Promise.all を参照してください。

6
Dan Beaulieu

上記のようにPromise.allを使用することをお勧めしますが、そのアプローチを避けたい場合は、forまたは他のループを実行できます。

const arr = [1,2,3,4,5];
let resultingArr = [];
for (let i in arr){
  await callAsynchronousOperation(i);
  resultingArr.Push(i + 1)
}
0
Beckster