Cloudflare Workers は、非同期操作を通じて一貫性を保つインメモリストアを作るための、Node.js AsyncLocalStorage ↗ API のサブセットを実装しています。
import { AsyncLocalStorage } from "node:async_hooks";
const asyncLocalStorage = new AsyncLocalStorage();new AsyncLocalStorage(): AsyncLocalStorage- 新しい
AsyncLocalStorageインスタンスを返します。
- 新しい
-
getStore(): any- 現在のストアを返します。
asyncLocalStorage.run()で初期化した非同期コンテキストの外から呼ぶと、undefinedを返します。
- 現在のストアを返します。
-
run(storeany, callbackfunction, ...argsarguments): any- コンテキスト内で関数を同期的に実行し、その戻り値を返します。ストアはコールバック関数の外からはアクセスできません。コールバック内で作成した非同期操作からはストアにアクセスできます。省略可能な
argsはコールバック関数へ渡されます。コールバック関数がエラーをスローすると、run()もそのエラーをスローします。
- コンテキスト内で関数を同期的に実行し、その戻り値を返します。ストアはコールバック関数の外からはアクセスできません。コールバック内で作成した非同期操作からはストアにアクセスできます。省略可能な
-
exit(callbackfunction, ...argsarguments): any- コンテキストの外で関数を同期的に実行し、その戻り値を返します。このメソッドは、
storeの値をundefinedにしてrun()を呼ぶのと同等です。
- コンテキストの外で関数を同期的に実行し、その戻り値を返します。このメソッドは、
-
AsyncLocalStorage.bind(fn): functionbind()呼び出し時点の非同期コンテキストをキャプチャし、渡された関数を呼ぶ前にそのコンテキストへ入る関数を返します。
-
AsyncLocalStorage.snapshot(): functionsnapshot()呼び出し時点の非同期コンテキストをキャプチャし、指定した関数を呼ぶ前にそのコンテキストへ入る関数を返します。
import { AsyncLocalStorage } from 'node:async_hooks';
const asyncLocalStorage = new AsyncLocalStorage();
let idSeq = 0;
export default {
async fetch(req) {
return asyncLocalStorage.run(idSeq++, () => {
// Simulate some async activity...
await scheduler.wait(1000);
return new Response(asyncLocalStorage.getStore());
});
}
};この API は、複数の AsyncLocalStorage インスタンスを同時に使えます。
import { AsyncLocalStorage } from 'node:async_hooks';
const als1 = new AsyncLocalStorage();
const als2 = new AsyncLocalStorage();
export default {
async fetch(req) {
return als1.run(123, () => {
return als2.run(321, () => {
// Simulate some async activity...
await scheduler.wait(1000);
return new Response(`${als1.getStore()}-${als2.getStore()}`);
});
});
}
};Promise が拒否され、その拒否が未処理のとき、非同期コンテキストは 'unhandledrejection' イベントハンドラーへ伝播します。
import { AsyncLocalStorage } from "node:async_hooks";
const asyncLocalStorage = new AsyncLocalStorage();
let idSeq = 0;
addEventListener("unhandledrejection", (event) => {
console.log(asyncLocalStorage.getStore(), "unhandled rejection!");
});
export default {
async fetch(req) {
return asyncLocalStorage.run(idSeq++, () => {
// Cause an unhandled rejection!
throw new Error("boom");
});
},
};import { AsyncLocalStorage } from "node:async_hooks";
const als = new AsyncLocalStorage();
function foo() {
console.log(als.getStore());
}
function bar() {
console.log(als.getStore());
}
const oneFoo = als.run(123, () => AsyncLocalStorage.bind(foo));
oneFoo(); // prints 123
const snapshot = als.run("abc", () => AsyncLocalStorage.snapshot());
snapshot(foo); // prints 'abc'
snapshot(bar); // prints 'abc'import { AsyncLocalStorage } from "node:async_hooks";
const als = new AsyncLocalStorage();
class MyResource {
#runInAsyncScope = AsyncLocalStorage.snapshot();
doSomething() {
this.#runInAsyncScope(() => {
return als.getStore();
});
}
}
const myResource = als.run(123, () => new MyResource());
console.log(myResource.doSomething()); // prints 123AsyncResource ↗ クラスは、Node.js の非同期コンテキスト追跡 API の一部で、独自の非同期コンテキストを作れます。AsyncResource を拡張したオブジェクトは、Promise とほぼ同じ方法で非同期コンテキストを伝播できます。
よりよい方法は AsyncLocalStorage.snapshot() と AsyncLocalStorage.bind() です。AsyncResource は、Node.js との後方互換性のためだけに提供されています。
import { AsyncResource, AsyncLocalStorage } from "node:async_hooks";
const als = new AsyncLocalStorage();
class MyResource extends AsyncResource {
constructor() {
// The type string is required by Node.js but unused in Workers.
super("MyResource");
}
doSomething() {
this.runInAsyncScope(() => {
return als.getStore();
});
}
}
const myResource = als.run(123, () => new MyResource());
console.log(myResource.doSomething()); // prints 123-
new AsyncResource(typestring, optionsAsyncResourceOptions): AsyncResource- 新しい
AsyncResourceを返します。重要な点として、コンストラクター引数は Node.js のAsyncResource実装では必須ですが、Workers では使われません。
- 新しい
-
AsyncResource.bind(fnfunction, typestring, thisArgany)- 指定した関数を、現在の非同期コンテキストにバインドします。
-
asyncResource.bind(fnfunction, thisArgany)- 指定した関数を、この
AsyncResourceに関連付けられた非同期コンテキストにバインドします。
- 指定した関数を、この
-
asyncResource.runInAsyncScope(fnfunction, thisArgany, ...argsarguments)- 指定した引数で、この
AsyncResourceに関連付けられた非同期コンテキスト内で関数を呼びます。
- 指定した引数で、この
-
Workers が提供する
AsyncLocalStorage実装は、意図的にasyncLocalStorage.enterWith()↗ とasyncLocalStorage.disable()↗ メソッドをサポートしていません。 -
Workers は、Node.js の
AsyncLocalStorage実装の土台であるasync_hooks↗ API 全体は実装していません。 -
Workers は、Node.js で許されているような、トリガーコンテキストを明示して
AsyncResourceを作成する機能は実装していません。そのため、新しいAsyncResourceは常に、作成時の非同期コンテキストにバインドされます。 -
Thenable(
then()メソッドを公開する、Promise ではないオブジェクト)は、AsyncLocalStorage使用時に完全にはサポートされません。Thenable を扱うときは、代わりにAsyncLocalStorage.snapshot()↗ で現在のコンテキストのスナップショットを取得してください。