◆ for-await-of にすると自動でループ変数に入れる前に await される
◆ 中で await してもあまり変わらないけど Promise の then などが使われないとわかるだけでも読みやすくなる

Chrome 66 で for await of 構文が使えるようになりました
ということで for 系ループと async についてまとめてみます

wait

まずは待機させるための wait 関数を用意します
const wait = msec => new Promise(r => setTimeout(r, msec))

使い方はこういう感じです
!async function(){
console.log(Date.now() % 100000 / 1000, "スタート")
await wait(1000)
console.log(Date.now() % 100000 / 1000, "1 秒経過")
}()
50.255 "スタート"
51.256 "1 秒経過"
指定したミリ秒だけ待機して解決される Promise を返します
async 関数内で使える await キーワードを式に指定すると式の評価結果が Promise の場合は解決されるまでそこで待機して Promise の結果を取り出せます
今回は待機するだけで Promise の結果の値がないので await の結果を代入することなくただ await するだけです

for await of

新しく使えるようになった for await of 構文はこういう使い方です
!async function(){
console.log(Date.now() % 100000 / 1000)
for await (const x of [wait(1000), wait(2000), wait(3000)]){
console.log(Date.now() % 100000 / 1000)
}
}()
2.567
3.568
4.568
5.568

for of でループさせる対象の要素それぞれが Promise のときに それぞれがループ変数に代入されるときに await されます
x には wait(1000) の結果の Promise を await した結果が入ります

また
[wait(1000), wait(2000), wait(3000)]
は配列を作るときに 3 つの Promise が作られるので 1 秒待った後に 2 秒待って そのあとに 3 秒待つとはなりません
for await of 構文が実行されるタイミングから 1 秒後と 2 秒後と 3 秒後に解決される 3 つの Promise が作られるので 解決される時間差は 1 秒です
なので結果は 1 秒ずつ表示されています

ところで await はコンソールで使う場合はトップレベルで書けますが for await は今のところトップレベルで書けないようです

Unexpected reserved word

と言われてしまいます

これまでの await

for await of がないこれまでの機能で同じ動きをさせるにはこうなります
!async function(){
console.log(Date.now() % 100000 / 1000)
for(const p of [wait(1000), wait(2000), wait(3000)]){
const x = await p
console.log(Date.now() % 100000 / 1000)
}
}()
64.783
65.783
66.783
67.784
内側で await をさせるだけです
for await of はちょっと短くかけるだけでそこまで大きく便利になるものではありません

x を使わないから 1 行余分になっていますが Promise の中の値を使う場合は x のところに代わりに 「await p」 (p は Promise 型の値) と書くだけでいいので たいていの場合はもっと気にならないと思います

for await(const x of [Promise.resolve(100)]){
console.log(x)
}
// 100

for(const p of [Promise.resolve(100)]){
console.log(await p)
}
// 100

どうせ待機するなら for await と最初に宣言しておくほうが読みやすいので 使えるなら使うに越したことはないのですけどね
Promise のまま受け取ると中で then してるかもとか 余計な考える事が増えます
下の方に書きますが then があるとその関数が終わっても 非同期で後でやる処理が存在するので流れを追うのが大変になります

Promise.all

for await of では前から順に Promise が解決されたタイミングで実行されました
全部終わってから実行するなら昔からある Promise.all でできます
!async function(){
console.log(Date.now() % 100000 / 1000)
for(const x of await Promise.all([wait(1000), wait(2000), wait(3000)])){
console.log(Date.now() % 100000 / 1000)
}
}()
32.843
35.843
35.843
35.845

配列を Promise.all に渡せば それぞれの Promise 全部が解決されると解決される Promise が返ってきます
なので Promise.all から受け取れる Promise ひとつだけをみて await します
この Promise の中の値はそれぞれの Promise の中の値の配列になっているので それを for of 文でループします
of の値が await 済みなので for 文のループが始まる前に await で待機しています

全部が終わってからループするので時間は全部同じタイミングになっています

先に後で解決される Promise が来ると

これまでの for await of の例は解決される順番どおりに配列が並んでいました
配列の前の方に解決されるのが遅い Promise が来た場合は それが解決されるまで後ろの Promise も待機することになります
!async function(){
console.log(Date.now() % 100000 / 1000)
for await (const x of [wait(5000), wait(1000)]){
console.log(Date.now() % 100000 / 1000)
}
}()
70.165
75.54
75.54

wait(1000) のほうはすぐに終わっていても wait(5000) が解決されるまで実行されません
wait(5000) が解決されるときには wait(1000) は解決済みなので即 次のループも実行されます

並列にする

今回は wait なので Promise が終わる順番がわかります
しかし実際は順番がわからないことは多いです
そういうときに終わったものから順に処理させたいこともあります
配列順の直列ではなく並列に処理させるイメージです
Promise を返す関数を実行してる時点で fetch などのバックグラウンド処理は並行して実行されていますが 結果に対する処理が前の処理が終わるのを待っていては あまり効率がよくないですからね

then

ひとつは単純に then でそれぞれに終わったらやる処理を設定していくことです
await をしないのでブロックしません
!function(){
console.log(Date.now() % 100000 / 1000)
for(const p of [wait(5000), wait(1000)]){
p.then(e => console.log(Date.now() % 100000 / 1000))
}
}()
4.35
5.351
9.351

await

then なんて使いたくない 全部 await にしたい という場合は Promise の配列の forEach メソッドに async 関数を渡すことができます
!async function(){
console.log(Date.now() % 100000 / 1000)
;[wait(5000), wait(1000)].forEach(async p => {
const x = await p
console.log(Date.now() % 100000 / 1000)
})
}()
20.511
21.541
25.54

forEach に渡した関数は async 関数なので関数の実行自体は await を待たずに即完了します
なので 配列の全部の要素に対して await p が即実行された状態になっています
あとは それぞれが解決されたタイミングで続きの console.log が実行されます

今は全部の console.log が終わったタイミングが把握できませんが forEach を map に変えて その返り値の配列を Promise.all を通して await することで外側の即時関数の返り値の Promise で全部終わったことがわかります

await async function(){
console.log(Date.now() % 100000 / 1000)
await Promise.all([wait(5000), wait(1000)].map(async p => {
const x = await p
console.log(Date.now() % 100000 / 1000)
}))
}()
console.log(Date.now() % 100000 / 1000, "all done.")
6.357
7.361
11.359
11.36 "all done."