JavaScriptの非同期関数（async function）について part2

# 初めに
前回の続きです。

https://qiita.com/hu-yu/items/2bd2d6e2c5b5f60c33e7

# Memo

`Actions/States of Promise`：
　`(Unsettled)Pending`⇒`neither onFulfilled or onRejected`
　`(return resolve()⇒Settled)Fulfilled`⇒`onFulfilled(.then(onFulfilled))`
　`(return reject()/unexpected⇒Settled)Rejected`⇒`onRejected(.then(..., onRejected)/.catch())`



# async function
やっとですね。`async`と`await`のおかげで画期的な展開が迎えるようになりました。

`Thunk`や`co`の理解は一苦労してたけれど、`co`の使い方では幅広いデータタイプでもとても快く対応してくれています。しかし依然として改善される余地があれば向上が止まらないのです。

`co`は`yield`に`Thunk`か`Promise`しか受け入れられないことに対し、
`async`は`await`に解決された`Promise`か拒否された`Promise`、あるいは **`Promise`ではない値なら暗黙に`Promise`にしてから別のタスクキューに移させることによって非同期処理を実現します。**

https://es6.ruanyifeng.com/?search=asyncIterator&x=2&y=15#docs/async#%E5%9F%BA%E6%9C%AC%E7%94%A8%E6%B3%95

下は参考文章から取ったデモコードです。（一部練習のため変更あり）
```jsx
// example1
async function getStockPriceByName(name) {
  // function getStockName(str) {...}
  // function getStockPrice(stockName) {...}

  const stock = await getStockName(name);
  const stockPrice = await getStockPrice(stock);
  return stockPrice;
}
getStockPriceByName('goog').then((result) => {
  console.log(result);
});

// example2
function timeout(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}
async function waitToPrint(value, ms) {
  await timeout(ms);
  console.log(value);
}
waitToPrint('hello world', 1000);
// or
async function timeout(ms) {
  await new Promise((resolve) => {
    setTimeout(resolve, ms); // after "ms" seconds, execute resolve()
  });
}
async function waitToPrint(value, ms) {
  await timeout(ms);
  console.log(value);
}
// example3 - async function always returns promise
async function foo() {
  return 'abc'
}
foo().then((result) => {
  console.log(result);
});
// abc
// example4 - Error handling
async function foo() {
  throw new TypeError('Typo');
}
foo().then(
  result => console.log('resolve', result),
  error => { if (error instanceof TypeError) console.log('reject', error) }
)
```
下は書き方のデモコードです。
```jsx
// usage
// function declaration
async function foo() { }
// function expression
const foo = async function () { };
// arrow function
const foo = async () => { };

// object method
let obj = {
  async foo() {
    // something
  }
};
obj.foo().then();
// class method
class Storage {
  constructor() {
    // CacheStorage.open()
    this.cachePromise = caches.open('avatars');
  }
  async getAvatar(name) {
    const cache = await this.cachePromise;
    return cache.match(`/avatars/${name}.jpg`);
  }
}
const storage = new Storage();
storage.getAvatar('jude').then();
```

# async function with `then()`
`async`関数では内部コードすべての実行が完了し、返り値が解決された`Promise`か拒否された`Promise`だと約束されている。

```jsx
// demo
async function getTitle(url) {
  // get the response
  let response = await fetch(url);
  // wait until text is ready
  let html = await response.text();
  // return html title
  // return html.match(/<title>([\s\S]+)<\/title>/i)[1]; // the result is unexpected
  return html.match(/<title>([^<]+)<\/title>/i)[1];
}
getTitle('https://tc39.github.io/ecma262/').then(
  result => console.log(result),
  err => console.log(err)
);
// ECMAScript® 2023 Language&nbsp;Specification

// debugger
// this is the result when i use ".match(/<title>([\s\S]+)<\/title>/i)[1]"
// let str = `<title>ECMAScript® 2023 Language&nbsp;Specification</title><script src="ecmarkup.js?cac
// he=YeiTF_tp" defer=""></script></head><body><div id="shortcuts-help">
// <ul>
//   <li><span>Toggle shortcuts help</span><code>?</code></li>
//   <li><span>Toggle "can call user code" annotations</span><code>u</code></li>
// <li><span>Navigate to/from multipage</span><code>m</code></li>
//   <li><span>Jump to search box</span><code>/</code></li>
// </ul></div><div id="menu-toggle"><svg xmlns="http://www.w3.org/2000/svg" style="
// width:100%; height:100%; stroke:currentColor" viewBox="0 0 120 120">
//       <title>Menu`

// console.log(str.match(/<title>([\s\S]+)<\/title>/i)[1]);
// ECMAScript® 2023 Language&nbsp;Specification
// note: in nodejs, it does work very well, maybe the problem occurred in fetch?
```

# `await`
普通の関数でも`Promise`を返してから`then()`でコールバックを呼び出すことができますが`await`は`async`関数以外は作用しない。普通の関数では`await`を通して`resolve`された`Promise`を待ったり、あるいは`reject`された`Promise`のエラー処理したりするのができません。

一つ誤解されやすいところだと思いますが。

>The expression is resolved in the same way as Promise.resolve(), which means thenable objects are supported, and if expression is not a promise, it's implicitly wrapped in a Promise and then resolved.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#description

それは`await`を使えば`Promise`でない値を`Promise`オブジェクトに変換してくれるところです。

確かに`thenable`オブジェクトではカスタムの`then((resolve, reject))`メソッドを利用すれば解決された`Promise`として返し、それからも`.then()`や`.catch()`で`Promise`チェイン続くことができる。

しかし`await`本当の作用は、`Promise`でない値を`Promise`オブジェクトに包んで`Microtask`へ移行して非同期処理を行わせ、返り値を待つことです。詳しくは [**thenable vs. Promise (Microtask)**](https://qiita.com/hu-yu/items/54b767ea002d5489fdfd#thenable-vs-promise-microtask) のコードや解釈を参考にしていただければ幸いです。

```jsx
// is Promise
async function isPromise1() {
  let data = new Promise((resolve, reject) => {
    resolve('abc');
  });
  console.log(data instanceof Promise);
  data.then((result) => console.log(result));
}
// is Promise
async function isPromise2() {
  let data = Promise.resolve('abc');
  console.log(data instanceof Promise);
  data.then((result) => console.log(result));
}

// not Promise
async function notPromise1() {
  let data = await new Promise((resolve, reject) => {
    resolve('abc');
  });
  console.log(data instanceof Promise);
  // data.then((result) => console.log(result));
  // TypeError: data.then is not a function
}
// not Promise
async function notPromise2() {
  let data = await Promise.resolve('abc');
  console.log(data instanceof Promise);
  // data.then((result) => console.log(result));
  // TypeError: data.then is not a function
}

isPromise1(); // true
isPromise2(); // true
notPromise1(); // false
notPromise2(); // false
```
`await`から値がアサインされた変数は`Microtask Queue`から戻った値であり、`Promise`インスタンスではないため`then()`メソッドもとうぜん使えなくなる。

変数ではなく、`await`へアサインする前に`Promise`に使いましょう！
```jsx
// use then() after Promise, not variable
async function awaitPromiseChain() {
  let data = await Promise.resolve('abc')
    .then((result) => console.log(result));
}
awaitPromiseChain(); // abc
```

## `await` with reject (error handling)
`async`関数実行中、`await`が`reject`された`Promise`を受けるとすぐ`async`関数を中断する。
```jsx
// await with reject
async function foo() {
  await Promise.reject('something wrong'); // reject will suspend following execution
  console.log('not work');
}
async function foo1() {
  return 'it works';
}
foo().then((result) => console.log(result));
foo1().then((result) => console.log(result));
console.log('1');
// 1
// it works
// UnhandledPromiseRejection
```
確かに`async`関数は、普通の関数のように中断されるとキャッチされていないエラーがそのまま外側に投げプログラムが中断されることがないです。それにほかの`async`関数がいてもエラーに影響されず、未処理のエラーが最後一気に投げてくるだけです。
それでもエラーキャッチや処理が大事です。`async`関数内では一つの`await`に限られていなく、多くの場合はステップバイステップのように前の処理が確実に完成したうえ、それからの操作を実行していく、一種の確認作業でもあります。

外側からエラーをキャッチするのがいいけれどあまり意味しません。（上のように`async`関数はメインをブロッキングしない。）
なので`async`関数内`try...catch`で`await`を包んだり、`await`にアサインする値が`Promise`オブジェクトなら`.catch()`でキャッチしてもいいです。
```jsx
// error handling
async function foo() {
  await Promise.reject('something wrong'); // reject will suspend following execution
  console.log('not work');
}
foo()
  .then((result) => console.log(result))
  .catch((err) => console.log(err));
// something wrong

// better way
async function foo() {
  // to prevent suspend, catch the error in function first
  try {
    await Promise.reject('something wrong');
  } catch (err) {
    console.log(err);
    return await Promise.resolve('hello world');
  }
}
foo()
  .then((result) => console.log(result));
// something wrong
// hello world

// or
async function foo() {
  await Promise.reject('something wrong')
    .catch((err) => console.log(err));
  return await Promise.resolve('hello world');
}
foo()
  .then((result) => console.log(result));
// something wrong
// hello world
```

`try...catch`には実行してほしいコード、もし予定通りに実行してなかったりエラーだったり場合はキャッチして出力。
下のように`try...catch`の`await`にエラーになっても`return`に置かれた`await`は実行してくれます。
```jsx
// use try...catch
async function foo() {
  // catch error, and return resolved Promise
  try {
    await new Promise((resolve, reject) => {
      throw new Error('something wrong');
    });
  } catch (err) {
    console.log(err);
  }
  // return 'hello world';
  return await ('hello world'); // await has no effect in here
}
foo()
  .then((result) => console.log(result))
  .catch((err) => console.log(err));
// note: double check, if return value was reject, we can catch error here
// Error: something wrong
// hello world
```

外側に`.catch()`を使うことで、もし返り値がエラーか`reject`された`Promise`だった場合はキャッチしてくれます。
```jsx
// multiple actions
async function multipleAwait() {
  try {
    const value1 = await firstStep();
    const value2 = await secondStep(value1);
    const value3 = await thirdStep(value1, value2);
    console.log('Final: ', value3);
  } catch (err) {
    console.log(err);
  }
}
```
複数の`await`からエラーによって特定する場合は、エラーメッセージから分類してからどう処理していくかを決めるのもいいと思います。

https://qiita.com/hu-yu/items/628a5b9156633ad159f7#throw-error-message--rethrowing

```jsx
// retry with for Loop
const superagent = require('superagent');
const retryCounter = 3;

async function test() {
  let i;
  for (i = 0; i < retryCounter; ++i) {
    try {
      await superagent.get('http://google.com/this-throws-an-error');
      break;
    } catch (err) { }
  }
  console.log(i);
}
test(); // 3
```

# thenable vs. Promise (Microtask)
`thenable`オブジェクトというのは`then()`メソッド持ちのオブジェクトのことです。下は同じく参考文章から取った例です。

https://es6.ruanyifeng.com/?search=asyncIterator&x=2&y=15#docs/async#await-%E5%91%BD%E4%BB%A4

```jsx
// await with thenable
class SleepTime {
  constructor(timeout) {
    this.timeout = timeout;
  }
  then(resolve, reject) {
    const startTime = Date.now();
    setTimeout(
      () => resolve(Date.now() - startTime),
      this.timeout
    );
  }
}
(async () => {
  const sleepTime = await new SleepTime(999);
  console.log(sleepTime);
})();

function sleep(interval) {
  return new Promise((resolve) => {
    setTimeout(
      () => resolve(),
      interval);
  })
}
async function oneToFiveInAsync() {
  for (let i = 1; i <= 5; i++) {
    console.log(i);
    await sleep(1000);
  }
}
oneToFiveInAsync();
// 1
// 2
// 1007
// 3
// 4
// 5
```
出力結果にとても気になりますね。一番目の`async`関数は`IIFE`なのになぜ二番目の`async`関数`oneToFiveInAsync()`より遅くなるでしょうか。
前も少し触れていたが、非同期関数`Promise`や非同期APIら（`setTimeout/setInterval`など）は別々のキューに優先順で実行されるのです。

`Promise`は`Microtask`に、`setTimeout/setInterval`は`Macrotask`にタスクを実行する。実行が終わったら各自の`Queue`（キュー、隊列）に送られ、コールバックの実行を待ちます。
優先順としては`Microtask Queue`は常に`Macrotask Queue`より先、`Macrotask Queue`の実行が`Microtask Queue`がクリアするまでしない。そして`Microtask Queue`は`Call stack`がクリアするまで実行しない。

`Call stack > Microtask Queue > Macrotask Queue`
`Microtask Queue`は解決された`Promise`が順番通りに実行する隊列ですが、
`Macrotask Queue`は多くはタイマー持ち非同期APIのコールバック隊列なので、順序には意味を持たない。

ここから上の例の実行順の説明です。
自分の解釈が正しいかはかわかりませんが、説明に試してみたいと思います。
（`task`には番号づけて説明するが、`task Queue`は当時の実行順で書いています。）
`Call stack`：
`IIFE`⇒`new SleepTime(1000)`⇒`setTimeout()`⇒
`Macrotask (1) start, timer in IIEF is executing` 
(Is `Call stack` clear? No.
Is `Microtask Queue` clear? Yes.
Is `Macrotask Queue` clear? Yes.)
↓
`Call stack`：
`oneToFiveInAsync()`⇒`for Loop`
(Is `Call stack` clear? No.
Is `Microtask Queue` clear? Yes.
Is `Macrotask Queue` clear? Yes.)
↓
`Call stack`：
`for Loop (1/5) start`⇒`console.log(1)`⇒`sleep(1000)`⇒
`new Promise() in sleep function`⇒ **`Microtask (1) start`** ⇒
`setTimeout()`⇒`Macrotask (2) start, timer in Promise is executing`
(Is `Call stack` clear? Yes.
Is `Microtask Queue` clear? Yes.
Is `Macrotask Queue` clear? Yes. )
↓　**one second later**
`Macrotask (1) end, timer in IIEF had been executed`⇒`Macrotask Queue (1)`
`Macrotask (2) end, timer in Promise had been executed`⇒`Macrotask Queue (2)`
(Is `Call stack` clear? Yes.
Is `Microtask Queue` clear? Yes.
Is `Macrotask Queue` clear? No. )
↓
`Macrotask Queue (1) start, setTimeout callback anonymous executed`⇒
`resolve(Date.now() - startTime)`⇒ **`Microtask (2) start`**
(Is `Call stack` clear? Yes.
Is `Microtask Queue` clear? Yes.
Is `Macrotask Queue` clear? No. )
↓
`Macrotask Queue (2) start, setTimeout callback anonymous executed`⇒
`resolve()`⇒ **`Microtask (1) end`** ⇒
`return resolved Promise`⇒ **`Microtask Queue (1)`**
(Is `Call stack` clear? Yes.
Is `Microtask Queue` clear? No.
Is `Macrotask Queue` clear? Yes. )
↓
**`Microtask Queue (1) start & end`** ⇒`await sleep(1000)`⇒`for Loop (1/5) done`
　　(Asynchronous) **`Microtask (2) end`** ⇒ **`Microtask Queue (1)`**
(Is `Call stack` clear? **No.**
Is `Microtask Queue` clear? Yes.
Is `Macrotask Queue` clear? Yes. )
↓　**for loop is synchronous**
`Call stack`：
`for Loop (2/5) start`
(Is `Call stack` clear? No.
Is `Microtask Queue` clear? No.
Is `Macrotask Queue` clear? Yes. )
↓
`console.log(2)`⇒`sleep(1000)`⇒
`new Promise() in sleep function`⇒`Microtask (3) start`⇒
`setTimeout()`⇒`Macrotask (3) start, timer in Promise is executing`
↓
(Is `Call stack` clear? Yes.
Is `Microtask Queue` clear? No.
Is `Macrotask Queue` clear? Yes. )
**`Microtask Queue (1) start & end`** ⇒
`sleepTime = await new SleepTime(1000)`⇒`console.log(sleepTime)`
↓
(Is `Call stack` clear? Yes.
Is `Microtask Queue` clear? Yes.
Is `Macrotask Queue` clear? Yes. )
↓　**one second later**
`Macrotask (3) end, timer in Promise had been executed`⇒`Macrotask Queue (1)`
...
...とかなり自分勝手に解釈して書いてみました。
長くて読みづらいかもしれないが、ほかのスレッド／タスクキューとの相互作用と、レンダリングのタイミングや、非同期HTTPリクエストなども加えればもっと複雑になります。今の自分はとにかくこの三つの実行順に理解したいと思います。

同じ例で少し変更すれば全然違う結果が出てきました。
```jsx
(async () => {
  const sleepTime = await new SleepTime(0);
  console.log(sleepTime);
})();
...
// 1
// 5 // sleepTime
// 2
// 3
// 4
// 5
```
出力順番が変わったというのは、`new SleepTime(0)`が`sleep(1000)`より先にタイマーが終わりコールバックから`resolve()`によって解決された`Promise`が`Microtask Queue`隊列に入ってしまったわけです。

その理由を説明する前にまず`thenable`中の`setTimeout()`と`Promise`中の`setTimeout()`の動きを解釈してみたいと思います。

`thenable`の`new SleepTime()`は`setTimeout(() => resolve(), ms)`、タイマーの後`anonymous()`⇒`resolve()`により`Microtask (1)`が始まり、そして解決された`Promise`を`Microtask Queue`へ送る。
一方`sleep(1000)`は`new Promise()`実行の時点で`Microtask (2)`が始まり、そのあとタイマーから`anonymous()`⇒`resolve()`の実行により解決された`Promise`を`Microtask Queue`へ送るのです。
これは一番目の例でも二番目の例でも同じタスク順に沿って動作するのです。

もう気づいているかもしれませんが、**`Microtask Queue`の順番は`Microtask`のタスク順とは関係なく、先に処理が終わる方が`Microtask Queue`に入り、そのあと`call stack`へ移行し実行するのが`Microtask Queue`の順番から一番古いやつを取り出し実行していくのです**。

なおこの例では`new SleepTime(0)`から`new SleepTime(995)`まで順番が変わらず`sleepTime`がさきに出力されるのです。`new SleepTime(999)`なら実行速度により順番が上がったり下がったりしています。

この二つの例から`Call stack`、`Microtask Queue`、`Macrotask Queue`の検証によりタイマーが狂う理由、そして **`Promise`の非同期操作というのは`Microtask`にあること** 、今回ではうまく説明できたらいいと思います。

ここまで来て少し変な言い方がするかもしれませんが、こんな検証や説明で自分の理解が本当に正しいのかって自分でも自分に問いてます。まだ分からない部分がたくさんあって、何度も試行錯誤を重ねて自分の考えやロジックにチャレンジし、資料をどれだけ調べても読んでもやはり分からないことがありすぎて分からないまま放置しているのがよくあります。

ただ、この部分が大事だと直感的に感じて手が勝手に動いて、問題意識しながらテストの間でもだんだん面白くなってきました。そして自分も今回の検証からこれまで`Promise`のステータスやタスク、タスクキューへの認識があやふやだったところ、間違っている部分に気づいていましたので、何日もかけたけど自分のなかではとても有意義な時間でした。

https://ja.javascript.info/event-loop

下は同じ概念で簡潔化にしたコードです。
```jsx
// thenable vs. promise
class Thenable {
  then(resolve, reject) {
    setTimeout(
      () => resolve('I am Thenable Object'),
      1000
    )
  }
}
async function thenable() {
  let str = await new Thenable()
  console.log(str)
}
//
function PromiseToSet() {
  return new Promise((resolve, reject) => {
    setTimeout(
      () => resolve('I am Promise'),
      1000
    )
  })
}
async function test() {
  let str = await PromiseToSet();
  console.log(str);
}

thenable();
test();
// I am Thenable Object
// I am Promise
```

タイマーへが非同期の動きを観察するコードです。

https://www.jsv9000.app/?code=c2V0VGltZW91dChmdW5jdGlvbiBjKCkge30sIDApOwoKc2V0VGltZW91dChmdW5jdGlvbiBhKCkge30sIDEwMDApOwoKc2V0VGltZW91dChmdW5jdGlvbiBiKCkge30sIDUwMCk7CgpmdW5jdGlvbiBkKCkge30KCmQoKTs%3D

最後にもう少し自分なりにまとめてみたいと思います。
自分から見れば、JSの非同期操作／非同期処理の実現というのは、タスク順とは関係なくタスク各々の処理を実行するところです。しかし`Microtask Queue`隊列に入った実行待ちのコールバックは、実質上同期に動いています。

そうでないと、`Call stack > Microtask Queue > Macrotask Queue`のような優先度づけたり、`Microtask Queue`では順番通りに動く必要がありません。すべてが`single-thread`のベースからなるプロセスだからと思います。

# synchronous vs. asynchronous in `async function`
気になってしょうがないパートです。`async function`は普通の関数と違い、非同期`generator`に近い概念からなる関数というのがわかりますが、中身の動き、そして`await`を加えたらどうなるのでしょうか？

まずは`await`からです。`await`は右にある値が解決された`Promise`を期待するが、そうでない場合は一度`Promise`でラッピングして非同期処理を行わせます。しかし（`Microtask queue`から返した）結果を待たねばならないので下のコードが同期に動くしかありません。

（今から思い返せば、`await`は大きな処理ならばある意味で中身をブロッキング？...するかもしれないけど、`async`関数自体は`main()`の処理を妨げないように設計されていると思います。普通の関数とは一番の違いです。）
```jsx
// synchronous in async function
function getFoo() {
  return 'Foo'
}
function getBar() {
  return 'Bar'
}

async function syncTest() {
  let foo = await getFoo();
  let bar = await getBar();
  return [foo, bar];
}
syncTest().
  then((result) => console.log(result));
// [ 'Foo', 'Bar' ]
```
非同期の実現は`Microtask`にあるので、`Promise`で包んだら同時実行ができるようになります。
```jsx
// asynchronous in async function
async function asyncTest1() {
  let [foo, bar] = await Promise.all(
    [getFoo(), getBar()]
  );
  return [foo, bar];
}
asyncTest1()
  .then((result) => console.log(result));
// [ 'Foo', 'Bar' ]
```
解決された`Promise`が`Microtask queue`に移行し`then()`の中身の処理を実行していきます。`for Loop`は同期に動くしかありません。
```jsx
// Promise.allSettled(iterable)
async function stepByStep() {
  // asynchronous
  let data = Promise.allSettled(
    [getFoo(), getBar(), Promise.reject('something wrong')]
  );
  // console.log(data instanceof Promise); // true

  // asynchronous
  data
    .then((result) => {
      // synchronous
      for (let obj of result) {
        if (obj.status === 'fulfilled') {
          console.log(obj.value);
        } else {
          console.log(obj.reason);
        }
      }
    });
}
stepByStep();
// Foo
// Bar
// something wrong
```

ここから`resolved Promise`（`resolve()`）と`unsettled Promise`（`Promise()`）の動きが気になって、
```jsx
// asynchronous with synchronous
function test() {
  // asynchronous => Promise.resolve(resolved Promise) => Microtask Queue(then(onFulfilled[, onRejected]))
  // synchronous => then(onFulfilled()) => for Loop => Call stack
  return Promise.resolve(['Foo', 'Bar']).then(
    (result) => {
      for (let i = 0; i < result.length; i++) {
        console.log(result[i]);
      }
    }
  );
}
test();
// Foo
// Bar
```
（ここは`await`使う必要がない、一貫性のために`async`を取りました。）
注釈が長すぎて読みづらいと思う方がいるかもしれないので、非同期の概念を教えてくれた **Philip Roberts** 氏が作ったサイトを借りて、ヴィジュアル化したシミュレーションは下にあります。（`async`キーワードがサポートされていませんが。）

https://www.jsv9000.app/?code=ZnVuY3Rpb24gdGVzdCgpIHsNCiAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShbJ0ZvbycsICdCYXInXSkudGhlbigNCiAgICAocmVzdWx0KSA9PiB7DQogICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHJlc3VsdC5sZW5ndGg7IGkrKykgew0KICAgICAgICBjb25zb2xlLmxvZyhyZXN1bHRbaV0pOw0KICAgICAgfQ0KICAgIH0NCiAgKTsNCn0NCnRlc3QoKTs%3D

```jsx
function test() {
  // asynchronous => Promise => Microtask, resolved Promise => Microtask queue(then())
  // synchronous => then(onFulfilled()) => for Loop => Call stack
  return new Promise((resolve) => {
    resolve(['Foo', 'Bar'])
  }).then((result) => {
    for (let i = 0; i < result.length; i++) {
      console.log(result[i])
    }
  });
}
test();
// Foo
// Bar
```
https://www.jsv9000.app/?code=ZnVuY3Rpb24gdGVzdCgpIHsNCiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7DQogICAgcmVzb2x2ZShbJ0ZvbycsICdCYXInXSkNCiAgfSkudGhlbigocmVzdWx0KSA9PiB7DQogICAgZm9yIChsZXQgaSA9IDA7IGkgPCByZXN1bHQubGVuZ3RoOyBpKyspIHsNCiAgICAgIGNvbnNvbGUubG9nKHJlc3VsdFtpXSkNCiAgICB9DQogIH0pOw0KfQ0KdGVzdCgpOw%3D%3D


ここからまた`await`に戻ります。
非同期`Promise`と非同期API`setTimeout(callback, timer)`に`await`を加えたらどうなるでしょう。
```jsx
// asynchronous with asynchronous
async function test() {
  // asynchronous => Promise => Microtask, resolved Promise => Microtask queue
  // asynchronous => setTimeout(callback, timer) => timer to Macrotask => callback to Macrotask queue =>
  //                 callback => resolve => Microtask => resolve() => resolved Promise => Microtask queue
  let str1 = new Promise((resolve) => {
    setTimeout(() => resolve('first'), 2000);
  });
  let str2 = new Promise((resolve) => {
    setTimeout(() => resolve('second'), 1000);
  });
  Promise.race([str1, str2]).then((result) => console.log(result));
}
test(); // second
//
// add "await"
// await make everything in async function acts synchronously
// because it needs to wait until Promise is resolved
async function test() {
  let str1 = await new Promise((resolve) => {
    setTimeout(() => resolve('first'), 2000);
  });
  let str2 = await new Promise((resolve) => {
    setTimeout(() => resolve('second'), 1000);
  });
  Promise.race([str1, str2]).then((result) => console.log(result));
}
test(); // first
```
やはり`await`の**待つ行為**は関数内の動きを同調にしてしまいます。
でもこれだけで`await`を使うのが非同期の意味がなくなるなんて思わないです。逆に言うと何か準備を整えてから次のステップに行くとき`await`を使うべきだと思います。それに`await`を通してエラーキャッチと処理、ブレークポイントとして使うのもありだと思います。そして最も大事なのは、`await`を通して後ろの値が解決された`Promise`ではなくても、**解決された`Promise`として`Microtask Queue`に移行し、外側に何が同期／非同期に動作しているコードがあってもブロッキングしない**ことです。
```jsx
// check: Is variable's problem? No.
async function test() {
  Promise.race([
    await new Promise((resolve) => {
      setTimeout(() => resolve('first'), 2000);
    }),
    await new Promise((resolve) => {
      setTimeout(() => resolve('second'), 1000);
    })
  ]).then((result) => console.log(result));
}
test(); // first
//
async function test() {
  Promise.race([
    new Promise((resolve) => {
      setTimeout(() => resolve('first'), 2000);
    }),
    new Promise((resolve) => {
      setTimeout(() => resolve('second'), 1000);
    })
  ]).then((result) => console.log(result));
}
test(); // second
```

# ES2022 Top-level `await` expression
`○ ES6 module  × CommonJs`

https://es6.ruanyifeng.com/?search=asyncIterator&x=2&y=15#docs/async#%E9%A1%B6%E5%B1%82%20await

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#top_level_await

ちょうど新しい使い方を見かけたので、一緒にまとめようと思います。
ES2022から最上位の`await`を追加しました。これまで非同期処理を使用するモジュールから一部の値を`import`すると`undefined`になるリスクがあるということで、
```jsx
// Problem
// awaiting.js
let output;
async function main() {
  const dynamic = await import(someMission); // import another module
  const data = await fetch(url);
  output = someProcess(dynamic.default, data);
}
main();
export { output };
// note: if we import awaiting.js before actions in async function
// haven't completed, output will be undefined

// usage.js
import { output } from './awaiting.js';

function outputPlusValue(value) {
  return output + value; // output could be undefined, it depends on loading
}
console.log(outputPlusValue(100));
```
最上位`await`が利用できるまでは、`Promise`として`export`するのが解決策のようでした。
```jsx
// alternative: export Promise
let output;
export default (async function main() {
  const dynamic = await import(someMission);
  const data = await fetch(url);
  output = someProcess(dynamic.default, data);
})();
export { output };
// note: here export Promise, when we use output in another file,
// we can use await to ensure it is loaded
```

そしてこれが最新の書き方です。
```jsx
// solution: top-level await
// awaiting.js
const dynamic = import(someMission);
const data = fetch(url);
export const output = someProcess((await dynamic).default, await data);
// note: use await to ensure modules are loaded

// usage.js
import { output } from '.awaiting.js';
function outputPlusValue(value) {
  return output + value; // now, output always has value
}
console.log(outputPlusValue(100));
```
（実はこの二つ書いたことないです（汗）。一応メモとして残します！）