async/awaitが手になじむまで色々書いてみるよ〜
現在運用中のプロジェクトのNodeのバージョンを7から8にあげたのでPromiseで書いていた箇所を徐々にasync/awaitに置き換えています。
簡単に書ける一方でPromsieに慣れすぎていたため、「これ並列処理になるんだっけ」とか、「てか、これ動く?」見たいなレベルで手になじまなかったので色々ためして馴染もうと思います。
利用するタイマー関数
function timer(ms, name) { console.log(`name: ${name} start!`) return new Promise((resolve, reject) => { setTimeout(() => resolve(name), ms) }) }
Case.1
- awaitを書いて非同期処理の関数を並べて書く
(async () => { const result1 = await timer(10000, 'a') const result2 = await timer(10000, 'b') console.log(result1, result2) })() // name: a start! // name: b start! // a b // 経過時間: 20000ms
Case.2
- awaitを書いて非同期処理の関数の戻り値でデストラクチャリング
(async () => { const [result1, result2] = [await timer(10000,'a'), await timer(10000, 'b')] console.log(result1, result2) })() // name: a start! // name: b start! // a b // 経過時間: 20000ms
Case.3
- Promise.allをawaitしてデストラクチャリング
(async () => { const [result1, result2] = await Promise.all([timer(10000, 'a'), timer(10000, 'b')]) console.log(result1, result2) })() // name: a start! // name: b start! // a b // 経過時間: 10000ms
Case.4
- 先にpromiseを作ってデストラクチャリング
(async () => { const p1 = timer(10000, 'a') const p2 = timer(10000, 'b') const [result1, result2] = [await p1, await p2] console.log(result1, result2) })() // name: a start! // name: b start! // a b // 経過時間: 10000ms
これは並列処理になる!
Case.5
- for文の中でawaitさせる
(async () => { for (let {ms, name} of [{ms: 10000, name: 'a'}, {ms: 10000, name: 'b'}]) { const result = await timer(ms, name) console.log(result) } })() // name: a start! // a // name: b start! // b // 経過時間: 20000ms
直列処理になる。
Case.5
- forEach内のラムダで実行する
(async () => { [{ms: 10000, name: 'a'}, {ms: 10000, name: 'b'}] .forEach(async ({ms, name}) => { const result = await timer(ms, name) console.log(result) }) console.log('c') })() // name: a start! // name: b start! // c // a // b
並列処理になるがcはラムダ内のawaitを待つことはない。
Case.6
- mapの戻りでawaitさせてみる
(async () => { const results = [{ms: 10000, name: 'a'}, {ms: 10000, name: 'b'}] .map(async ({ms, name}) => await timer(ms, name)) console.log(results) })() // name: a start! // name: b start! // [ Promise { <pending> }, Promise { <pending> } ] // 経過時間: (ほぼ)0ms
ただのpromiseの配列が帰ってくる。 当然だけど↓と同じ。
(async () => { const results = [{ms: 10000, name: 'a'}, {ms: 10000, name: 'b'}] .map(({ms, name}) => timer(ms, name)) console.log(results) // name: a start! // name: b start! // [ Promise { <pending> }, Promise { <pending> } ] })()
Case.8
(async () => { [{ms: 10000, name: 'a'}, {ms: 10000, name: 'b'}] .map(({ms, name}) => timer(ms, name)) .forEach(async promise => { const result = await promise console.log(result) }) console.log('c') })() // name: a start! // name: b start! // c // a // b
cは即時出力。timerは並列で実行されるが、forEachのラムダ内はawaitできる。
Case.9
- promiseの配列をPromise.allの引数に与える
(async () => { const sample = [{ms: 10000, name: 'a'}, {ms: 10000, name: 'b'}] const results = await Promise.all(sample.map(({ms, name}) => timer(ms, name)) console.log(results) })() // name: a start! // name: b start! // [ 'a', 'b' ] // 経過時間:10000ms
これが一番シンプルに並列処理の結果を直列に受け取れる気がする。
Case.10
- mapに渡すラムダ内でasync/awaitをする
(async () => { const sample = [{ms: 10000, name: 'a'}, {ms: 10000, name: 'b'}] const results = await Promise.all(sample.map(async ({ms, name}) => await timer(ms, name))) console.log(results) })() // name: a start! // name: b start! // [ 'a', 'b' ] // 経過時間:10000ms
そもそもtimerもasync functionもpromiseを返すので二重定義になって意味ない。
完全に理解した!!!!!