【TypeScript】Promise.allで頑張る
こんばんは。今回はPromise.allを使ってみます。MongoDBも使います。
記載の通り、配列に入ったPromiseを全部解決するまで待つという動きが出来るようになります。
Promise.allを使わないやりかた
import {MongoClient, MongoClientOptions} from "mongodb"; const uri:string = "mongodb://127.0.0.1:27017" const options:MongoClientOptions = {useUnifiedTopology:true,useNewUrlParser:true} const client = new MongoClient(uri,options); const dbName = "__test__"; const collectionName = "test_collec"; const initing = async (client:MongoClient) => { await client.connect(); const __test__ = client.db(dbName); const cursor = __test__.collection(collectionName).find(); const datas = []; while(await cursor.hasNext()){ datas.push(await cursor.next()); }; console.log(datas); await client.close(); return ; }; initing(client);
今回の話で最も重要なところはここの部分になります。
const datas = []; while(await cursor.hasNext()){ datas.push(await cursor.next()); }; console.log(datas);
datas
配列にDBから取得してきたデータを挿入してきているのですが、DBから取得してきている間はawaitしているので、その間の処理は完全に止まっています。
Promise.allを使ったやり方
import {MongoClient, MongoClientOptions} from "mongodb"; const uri:string = "mongodb://127.0.0.1:27017" const options:MongoClientOptions = {useUnifiedTopology:true,useNewUrlParser:true} const client = new MongoClient(uri,options); const dbName = "__test__"; const collectionName = "test_collec"; const initing = async (client:MongoClient) => { const cli = await client.connect(); const __test__ = cli.db(dbName); const cursor = __test__.collection(collectionName).find(); const datas = []; const count = await cursor.count(); for (let i = 1; i <= count; i++){ datas.push(cursor.next()); }; const promised = await Promise.all(datas); console.log(promised); await cli.close(); return ; }; initing(client);
変更部分は主にここ
const datas = []; const count = await cursor.count(); for (let i = 1; i <= count; i++){ datas.push(cursor.next()); }; const promised = await Promise.all(datas); console.log(promised);
while文をやめて、for文にしています。これはwhile内にあったcursor.hasNext()
の結果を待つという処理をやめて、単純にデータ内にある個数分データを取得するという判定に変更しています。そのfor文内で行っているdatas.push()
は、cursor.next()に対して結果の取得を待つという処理がなされていません。これらを取得するまでに待っていたものはデータの個数を持っているcursor.count()
だけです。
- while(await cursor.hasNext()){ - datas.push(await cursor.next()); - }; + const count = await cursor.count(); + for (let i = 1; i <= count; i++){ + datas.push(cursor.next()); + };
datasの中身は[Promise { <pending> }, Promise { <pending> }, Promise { <pending> }]
と言った感じになります。
そして、Promise.all()
でPromiseだらけのdatas
の取得を待ちます。この取得待ちは並列で行われるので、取得の待ち時間が少なくて住みます。そして、その結果をpromised
変数に代入してあげます。
ソースコード
今回のソースコードはこちら。MongoDBをローカルで建ててない人向けにDockerも作っています。
このように並列処理を書くのだ
沢山のPromiseがあるときは、一旦全部を配列に入れてあげて、Promise.allを使ってあげると便利に良さそう。