◆ for-await-of は Symbol.asyncIterator を見てる
◆ なければ Symbol.iterator

for await of って全然使ってなくて わざわざ構文にしなくても中で await すればいいじゃんと思ってました

function* gen(urls) {
for (const url of urls) {
yield fetch(url)
}
}

const urls = [
"https://www.google.com/",
"https://www.amazon.com/",
"https://github.com/",
]

for await (const res of gen(urls)) {
console.log(Date.now() % 10000, res.status, res.url)
}

for (const p of gen(urls)) {
const res = await p
console.log(Date.now() % 10000, res.status, res.url)
}
5381 200 "https://www.google.com/"
6083 200 "https://www.amazon.com/"
6907 200 "https://github.com/"
7037 200 "https://www.google.com/"
7268 200 "https://www.amazon.com/"
7946 200 "https://github.com/"

一つ変数は減り 見やすいのはたしかですがそれだけのために構文追加ってやりすぎ感があります

ですが それだけではなかったです

asyncIterator

for-of 文では Symbol.iterator を見ますが for-await-of では Symbol.asyncIterator というまた別のものをみていました

const obj = {}
obj[Symbol.iterator] = function*() { yield* [1, 2, 3] }
obj[Symbol.asyncIterator] = function*() { yield* [100, 200, 300] }

for (const v of obj) console.log(v)
for await (const v of obj) console.log(v)
1
2
3
100
200
300

Symbol.asyncIterator が未定義なら Symbol.iterator を使います

const obj = {}
obj[Symbol.iterator] = function*() { yield* [1, 2, 3] }
obj[Symbol.asyncIterator] = null

for (const v of obj) console.log(v)
for await (const v of obj) console.log(v)
1
2
3
1
2
3

逆の Symbol.iterator が未定義で Symbol.asyncIterator がある場合は for-await-of では問題なく動きますが for-of は動きません
obj is not iterable というエラーになります

単純に中で await するだけならわざわざ作る意味あったのかと思いましたが 見るシンボルが変わるのなら使い分けもできそうですし 有効な使いみちがあるような気もします

ちなみに AsyncGenerator のインスタンスは asyncIterator のみなので通常の for-of は使えません

const ai = async function*(){}()

ai[Symbol.iterator]
// undefined
ai[Symbol.asyncIterator]
// ƒ [Symbol.asyncIterator]() { [native code] }