Atomics.waitAsyncで非同期に共有メモリ上のデータを待機する
Baseline 2025にAtomics.waitAsyncが追加されました。Atomics.waitの非同期版のメソッドで、メインスレッドで共有メモリ上のデータを待機したい場合に便利です。
はじめに
Atomics.pauseに続き、Atomics.waitAsyncがBaseline 2025に追加されました。
AtomicsとAtomics.pauseについての簡単な説明はAtomicsで共有メモリ上のデータを安全に取り扱うをご覧ください。
この記事ではAtomics.waitAsyncについて解説します。
Atomics.waitAsync
Atomics.waitAsyncは名前の通り、Atomics.waitの非同期バージョンです。
waitAsyncは非同期にnotifyを待機するので、プロセスをブロックしません。そのため、メインスレッドでも利用できる利点を持ちます。
waitAsyncは、第1引数にSharedArrayBufferを元にしたInt32ArrayまたはBigInt64Array、第2引数にその配列内のインデックスを受け取ります。
第3引数には、引数の配列とインデックスが指す位置に存在することを期待する値を渡します。
最後に、任意の第4引数としてタイムアウト時間(ミリ秒)を指定できます。
const sab = new SharedArrayBuffer(4);
const int32 = new Int32Array(sab);
// int32の0番目の値が0であることを期待して待機、タイムアウトは1秒
const result = Atomics.waitAsync(int32, 0, 0, 1000);
非同期な処理を行うメソッドですが、戻り値は同期的で、valueがPromiseかどうかを示すasyncプロパティと、waitAsyncの結果を表すvalueプロパティを持つオブジェクトを返します。
TypeScriptでの型定義を考えると以下のようになります。
type ReturnValue =
| { async: false; value: "not-equal" | "timed-out" }
| { async: true; value: Promise<"ok" | "timed-out"> };
{ async: false; value: "not-equal" }が返される時は、引数の配列とインデックスが指す位置に存在する値が第3引数で渡した値と異なっていた場合です。
{ async: false; value: "timed-out" }が返される時は、、タイムアウトが0ミリ秒に指定されていた場合です。
{ async: true; value: Promise<"ok" | "timed-out"> }が通常返されるであろう値で、notifyによって呼び出された場合に"ok"、notifyが呼び出される前にタイムアウトした場合に"timed-out"を返すvalueがPromiseに包まれて格納されています。
const sab = new SharedArrayBuffer(4);
const int32 = new Int32Array(sab);
const result = Atomics.waitAsync(int32, 0, 0, 1000);
if (result.value === 'not-equal') {
// 指定した位置に存在する値が期待した値と異なる場合の処理
}
if (result.value === 'timed-out') {
// タイムアウト時間が0ミリ秒に指定された場合の処理
}
if (result.async) {
result.value.then(
(value) => {
if (value == 'ok') {
// notifyによって呼び出された場合の処理
} else {
// タイムアウトした場合の処理
}
});
}
考えられる例外はnot-equalのパターンぐらいで、他には考えられないのでvalueがrejectされることはありません。
おわりに
Atomicsの新しいメソッド、waitAsyncについて解説しました。
Atomics.waitが同期的にnotifyを待機するのに対して、waitAsyncは非同期にnotifyを待機できるので、メインスレッドで共有メモリ上のデータを待機したい場合に便利です。