okaryo.log

JavaScriptのforEachでは非同期処理を待ってくれなくてハマった | okaryo.log

JavaScriptのforEachでは非同期処理を待ってくれなくてハマった

    #JavaScript

はじめに

昨日公開したGatsbyプラグインgatsby-plugin-satorareを作っているときにハマったのでメモしておく。ちなみに開発ブログは以下。

どこでハマったか

Nodeの配列内のそれぞれの要素に対しOG画像を生成する処理をした際に、forEachを利用した。

nodes.forEach(async (node) => {
  const image = await generateImage()
  ...
})

これをビルドして動作確認していたところ、以下のようなエラーが出た。

BindingError: Expected null or instance of Node, got an instance of Node

エラーの原因はさっぱりだったが、エラー文で検索をかけると以下のZennのScrapを見つけた。

この中ではvercel/satoriを使用してSVG画像を生成する処理をPromise.allを使って並列で処理しようとしたところ上記のエラーが出ており、順次実行するようにすることでエラーを解消できたとのこと。

自分は並列処理をしているつもりはなかったが、forEachを使うことでそうなってしまっているのかと思って調べてみると記事のタイトルの通りforEachは非同期処理を待ってくれないとのことだった。

メモ: forEach は同期関数を期待します。

forEach はプロミスを待ちません。forEach のコールバックとしてプロミス (または非同期関数) を使用する場合は、その意味合いを理解しておくようにしてください。

解決法

forEachの代わりにforを使うことで解決した。これで画像処理が逐次的に処理されるようになり、上記のエラーは出なくなった。

for (const node of nodes) {
  const image = await generateImage()
  ...
}

おわり

順番を待つ必要がない処理であればforEachを使っても良いと思うし、今回の画像処理などはまさに使う場面だろう。ただ、たまたまライブラリの仕様上それが許されず、たまたまforEachのこの特性を知ることになった。

二度と引っかかりたくない。


関連記事
最新記事
プロモーション

This site uses Google Analytics.