JavaScript:awaitで取得するデータのキャッシュをどう実現する?
問題
複数の処理が同時に実行されている状態で、「データがない時は取りに行く」というのをawaitで実装しようとすると、データを取りに行っている間に、さらに他の処理がそのデータを取りに行ってしまうことがある。
thundering herd problem とか cache stampede と呼ばれるとのこと。
対応
データ取得中 Map とデータキャッシュ用 Map の二本立てにする。
データ取得用 Promise をデータ取得中 Map に記録する。
データが見つからない場合
Promise が見つからない場合
データ取得用 Promise を作る。
データ取得用 Promise をデータ取得中 Map に保存。
データ取得用 Promise の完了を待つ。
完了後
データ取得用 Promise をデータ取得中 Map から削除する。
データキャッシュ用 Map にデータを保存する。
データはそのまま使う。
Promise が見つかった場合
Promise の完了を待つ。(待たずに、キャッシュから読み出す方がいいかもしれない。)
完了後
データキャッシュ用 Map からデータを読み出す。
JavaScript はシングルスレッドなので Map に対するロックは不要。
オブジェクトもGCで自動的に消えるので Map から削除するだけであとは特に何もしなくてよい。