javascript で type=module下であるならば top level await が有効となっているのだから無限ループで 処理書いてもいいよね

というわけで javascript のアイディアの話です。 setTimeout でループを書いている旧世代の処理を 無限ループで書いてみようという話となります。

## setTimeout のループ

具体的にはこれまではこう書いていたところを

```js
function loopAction() {
  // doing
  setTimeout(loopAction, 500);
}
loopAction();
```

こう書いてみませんか？

```js
while(true) {
  // doing
  await new Promise(resolve => setTimeout(resolve, 500));
}
```

という話です。

これはいろいろと応用が利きまして

## 画像の読み込み

画像の読み込みを こう書いていたものを

```js
const srcUrl = "画像のファイルパス";
const image = new Image();
image.addEventListener('error', ({error}) => {
   // doing error process
});
Image.addEventListener('load',({target:image}) => {
  // doing load complete process
}
Image.src = srcUrl;
```

こう書くことができます。

```js
const srcUrl = "画像のファイルパス";
try {
  const image = await new Promise((resolve, reject) => {
    const image = new Image();
    image.addEventListener('error', ({error}) => reject(error));
    image.addEventListener('load', ({target}) => resolve(target));
    image.src = srcUrl;
  });
  // doing load complete process
}  catch (error) {
  // doing error process
}
```

この Image を使いまわししたいとなるなら次の様に書いたらいいと思います。
addEventListener の options に signal を指定すると abort 時に解除してくれます。

```js
const srcUrl = "画像のファイルパス";
try {
  const controller = new AbortController();
  let image;
  try {
    const signal = controller.signal;
    image = await new Promise((resolve, reject) => {
      signal.throwIfAborted()
      signal.addEventListener('abort', ({target}) => reject(target.reason));
      const image = document.getElementById('使いまわす image の id');
      image.addEventListener('error', ({error}) => reject(error), {signal});
      image.addEventListener('load', ({target}) => resolve(target), {signal});
      image.src = srcUrl;
    });
  } finally {
    controller.abort();
  }
  // doing load complete process
} catch (error) {
  // doing error process
}
```

https://developer.mozilla.org/ja/docs/Web/API/EventTarget/addEventListener#options

これによりイベントは処理後にちゃんと解除までされます。

もしも let image が気持ち悪いのであれば次の様に書いても同様の動作となります。

```js
const srcUrl = "画像のファイルパス";
try {
  const controller = new AbortController();
  const signal = controller.signal;
  const image = await new Promise((resolve, reject) => {
    signal.throwIfAborted()
    signal.addEventListener('abort', ({target}) => reject(target.reason));
    const image = document.getElementById('使いまわす image の id');
    image.addEventListener('error', ({error}) => reject(error), {signal});
    image.addEventListener('load', ({target}) => resolve(target), {signal});
    image.src = srcUrl;
  }).finally(() =>  controller.abort());
  // doing load complete process
} catch (error) {
  // doing error process
}
```

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally

Promise の finally は戻り値を変更せずに resolve / reject どっちの場合でも処理されるメソッドな為、こういう際に利用できます。

## ファイルの読み込み

ファイルの読み込みも昔は下記の様に書いていたのですが

```js
const file = event.target.files[0];
const reader = new FileReader();
reader.addEventListener('error', ({target: {error}}) => {
  // doing error process
});
reader.addEventListener('load', ({target: {result}}) => {
  // doing load complete process
});
reader.readAsArrayBuffer();
```

https://developer.mozilla.org/ja/docs/Web/API/FileReader/readAsArrayBuffer

今ならこう書けます。

```js
const file = event.target.files[0];
try {
  const result = await new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.addEventListener('error', ({target: {error}}) => reject(error));
    reader.addEventListener('load', ({target: {result}}) => resolve(result));
    reader.readAsArrayBuffer();
  });
  // doing load complete process
} catch (error) {
  // doing error process
}
```

いえ、 そもそも Blob に arrayBuffer() が生えているので これでいいです。

```js
const file = event.target.files[0];
try {
  const result = await file.arrayBuffer();
  // doing load complete process
} catch (error) {
  // doing error process
}
```

https://developer.mozilla.org/ja/docs/Web/API/Blob/arrayBuffer

以上。