• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<!DOCTYPE html>
2<html lang="en">
3<head>
4  <meta charset="utf-8">
5  <meta name="viewport" content="width=device-width">
6  <meta name="nodejs.org:node-version" content="v18.20.1">
7  <title>Asynchronous context tracking | Node.js v18.20.1 Documentation</title>
8  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:400,700,400italic&display=fallback">
9  <link rel="stylesheet" href="assets/style.css">
10  <link rel="stylesheet" href="assets/hljs.css">
11  <link rel="canonical" href="https://nodejs.org/api/async_context.html">
12  <script async defer src="assets/api.js" type="text/javascript"></script>
13  <style>@media(max-width:1080px){.with-73-chars>.js-flavor-selector{float:none;margin:0 0 1em auto;}}@media(max-width:686px){.with-58-chars>.js-flavor-selector{float:none;margin:0 0 1em auto;}}@media(max-width:1072px){.with-72-chars>.js-flavor-selector{float:none;margin:0 0 1em auto;}}@media(max-width:654px){.with-54-chars>.js-flavor-selector{float:none;margin:0 0 1em auto;}}@media(max-width:598px){.with-47-chars>.js-flavor-selector{float:none;margin:0 0 1em auto;}}</style>
14</head>
15<body class="alt apidoc" id="api-section-async_context">
16  <div id="content" class="clearfix">
17    <div id="column2" class="interior">
18      <div id="intro" class="interior">
19        <a href="/" title="Go back to the home page">
20          Node.js
21        </a>
22      </div>
23      <ul>
24<li><a href="documentation.html" class="nav-documentation">About this documentation</a></li>
25<li><a href="synopsis.html" class="nav-synopsis">Usage and example</a></li>
26</ul>
27<hr class="line">
28<ul>
29<li><a href="assert.html" class="nav-assert">Assertion testing</a></li>
30<li><a href="async_context.html" class="nav-async_context active">Asynchronous context tracking</a></li>
31<li><a href="async_hooks.html" class="nav-async_hooks">Async hooks</a></li>
32<li><a href="buffer.html" class="nav-buffer">Buffer</a></li>
33<li><a href="addons.html" class="nav-addons">C++ addons</a></li>
34<li><a href="n-api.html" class="nav-n-api">C/C++ addons with Node-API</a></li>
35<li><a href="embedding.html" class="nav-embedding">C++ embedder API</a></li>
36<li><a href="child_process.html" class="nav-child_process">Child processes</a></li>
37<li><a href="cluster.html" class="nav-cluster">Cluster</a></li>
38<li><a href="cli.html" class="nav-cli">Command-line options</a></li>
39<li><a href="console.html" class="nav-console">Console</a></li>
40<li><a href="corepack.html" class="nav-corepack">Corepack</a></li>
41<li><a href="crypto.html" class="nav-crypto">Crypto</a></li>
42<li><a href="debugger.html" class="nav-debugger">Debugger</a></li>
43<li><a href="deprecations.html" class="nav-deprecations">Deprecated APIs</a></li>
44<li><a href="diagnostics_channel.html" class="nav-diagnostics_channel">Diagnostics Channel</a></li>
45<li><a href="dns.html" class="nav-dns">DNS</a></li>
46<li><a href="domain.html" class="nav-domain">Domain</a></li>
47<li><a href="errors.html" class="nav-errors">Errors</a></li>
48<li><a href="events.html" class="nav-events">Events</a></li>
49<li><a href="fs.html" class="nav-fs">File system</a></li>
50<li><a href="globals.html" class="nav-globals">Globals</a></li>
51<li><a href="http.html" class="nav-http">HTTP</a></li>
52<li><a href="http2.html" class="nav-http2">HTTP/2</a></li>
53<li><a href="https.html" class="nav-https">HTTPS</a></li>
54<li><a href="inspector.html" class="nav-inspector">Inspector</a></li>
55<li><a href="intl.html" class="nav-intl">Internationalization</a></li>
56<li><a href="modules.html" class="nav-modules">Modules: CommonJS modules</a></li>
57<li><a href="esm.html" class="nav-esm">Modules: ECMAScript modules</a></li>
58<li><a href="module.html" class="nav-module">Modules: <code>node:module</code> API</a></li>
59<li><a href="packages.html" class="nav-packages">Modules: Packages</a></li>
60<li><a href="net.html" class="nav-net">Net</a></li>
61<li><a href="os.html" class="nav-os">OS</a></li>
62<li><a href="path.html" class="nav-path">Path</a></li>
63<li><a href="perf_hooks.html" class="nav-perf_hooks">Performance hooks</a></li>
64<li><a href="permissions.html" class="nav-permissions">Permissions</a></li>
65<li><a href="process.html" class="nav-process">Process</a></li>
66<li><a href="punycode.html" class="nav-punycode">Punycode</a></li>
67<li><a href="querystring.html" class="nav-querystring">Query strings</a></li>
68<li><a href="readline.html" class="nav-readline">Readline</a></li>
69<li><a href="repl.html" class="nav-repl">REPL</a></li>
70<li><a href="report.html" class="nav-report">Report</a></li>
71<li><a href="single-executable-applications.html" class="nav-single-executable-applications">Single executable applications</a></li>
72<li><a href="stream.html" class="nav-stream">Stream</a></li>
73<li><a href="string_decoder.html" class="nav-string_decoder">String decoder</a></li>
74<li><a href="test.html" class="nav-test">Test runner</a></li>
75<li><a href="timers.html" class="nav-timers">Timers</a></li>
76<li><a href="tls.html" class="nav-tls">TLS/SSL</a></li>
77<li><a href="tracing.html" class="nav-tracing">Trace events</a></li>
78<li><a href="tty.html" class="nav-tty">TTY</a></li>
79<li><a href="dgram.html" class="nav-dgram">UDP/datagram</a></li>
80<li><a href="url.html" class="nav-url">URL</a></li>
81<li><a href="util.html" class="nav-util">Utilities</a></li>
82<li><a href="v8.html" class="nav-v8">V8</a></li>
83<li><a href="vm.html" class="nav-vm">VM</a></li>
84<li><a href="wasi.html" class="nav-wasi">WASI</a></li>
85<li><a href="webcrypto.html" class="nav-webcrypto">Web Crypto API</a></li>
86<li><a href="webstreams.html" class="nav-webstreams">Web Streams API</a></li>
87<li><a href="worker_threads.html" class="nav-worker_threads">Worker threads</a></li>
88<li><a href="zlib.html" class="nav-zlib">Zlib</a></li>
89</ul>
90<hr class="line">
91<ul>
92<li><a href="https://github.com/nodejs/node" class="nav-https-github-com-nodejs-node">Code repository and issue tracker</a></li>
93</ul>
94    </div>
95
96    <div id="column1" data-id="async_context" class="interior">
97      <header class="header">
98        <div class="header-container">
99          <h1>Node.js v18.20.1 documentation</h1>
100          <button class="theme-toggle-btn" id="theme-toggle-btn" title="Toggle dark mode/light mode" aria-label="Toggle dark mode/light mode" hidden>
101            <svg xmlns="http://www.w3.org/2000/svg" class="icon dark-icon" height="24" width="24">
102              <path fill="none" d="M0 0h24v24H0z" />
103              <path d="M11.1 12.08c-2.33-4.51-.5-8.48.53-10.07C6.27 2.2 1.98 6.59 1.98 12c0 .14.02.28.02.42.62-.27 1.29-.42 2-.42 1.66 0 3.18.83 4.1 2.15A4.01 4.01 0 0111 18c0 1.52-.87 2.83-2.12 3.51.98.32 2.03.5 3.11.5 3.5 0 6.58-1.8 8.37-4.52-2.36.23-6.98-.97-9.26-5.41z"/>
104              <path d="M7 16h-.18C6.4 14.84 5.3 14 4 14c-1.66 0-3 1.34-3 3s1.34 3 3 3h3c1.1 0 2-.9 2-2s-.9-2-2-2z"/>
105            </svg>
106            <svg xmlns="http://www.w3.org/2000/svg" class="icon light-icon" height="24" width="24">
107              <path d="M0 0h24v24H0z" fill="none" />
108              <path d="M6.76 4.84l-1.8-1.79-1.41 1.41 1.79 1.79 1.42-1.41zM4 10.5H1v2h3v-2zm9-9.95h-2V3.5h2V.55zm7.45 3.91l-1.41-1.41-1.79 1.79 1.41 1.41 1.79-1.79zm-3.21 13.7l1.79 1.8 1.41-1.41-1.8-1.79-1.4 1.4zM20 10.5v2h3v-2h-3zm-8-5c-3.31 0-6 2.69-6 6s2.69 6 6 6 6-2.69 6-6-2.69-6-6-6zm-1 16.95h2V19.5h-2v2.95zm-7.45-3.91l1.41 1.41 1.79-1.8-1.41-1.41-1.79 1.8z"/>
109            </svg>
110          </button>
111        </div>
112        <div id="gtoc">
113          <ul>
114            <li class="pinned-header">Node.js v18.20.1</li>
115
116    <li class="picker-header">
117      <a href="#">
118        <span class="collapsed-arrow">&#x25ba;</span><span class="expanded-arrow">&#x25bc;</span>
119        Table of contents
120      </a>
121
122      <div class="picker"><div class="toc"><ul>
123<li><span class="stability_2"><a href="#asynchronous-context-tracking">Asynchronous context tracking</a></span>
124<ul>
125<li><a href="#introduction">Introduction</a></li>
126<li><a href="#class-asynclocalstorage">Class: <code>AsyncLocalStorage</code></a>
127<ul>
128<li><a href="#new-asynclocalstorage"><code>new AsyncLocalStorage()</code></a></li>
129<li><span class="stability_1"><a href="#static-method-asynclocalstoragebindfn">Static method: <code>AsyncLocalStorage.bind(fn)</code></a></span></li>
130<li><span class="stability_1"><a href="#static-method-asynclocalstoragesnapshot">Static method: <code>AsyncLocalStorage.snapshot()</code></a></span></li>
131<li><span class="stability_1"><a href="#asynclocalstoragedisable"><code>asyncLocalStorage.disable()</code></a></span></li>
132<li><a href="#asynclocalstoragegetstore"><code>asyncLocalStorage.getStore()</code></a></li>
133<li><span class="stability_1"><a href="#asynclocalstorageenterwithstore"><code>asyncLocalStorage.enterWith(store)</code></a></span></li>
134<li><a href="#asynclocalstoragerunstore-callback-args"><code>asyncLocalStorage.run(store, callback[, ...args])</code></a></li>
135<li><span class="stability_1"><a href="#asynclocalstorageexitcallback-args"><code>asyncLocalStorage.exit(callback[, ...args])</code></a></span></li>
136<li><a href="#usage-with-asyncawait">Usage with <code>async/await</code></a></li>
137<li><a href="#troubleshooting-context-loss">Troubleshooting: Context loss</a></li>
138</ul>
139</li>
140<li><a href="#class-asyncresource">Class: <code>AsyncResource</code></a>
141<ul>
142<li><a href="#new-asyncresourcetype-options"><code>new AsyncResource(type[, options])</code></a></li>
143<li><a href="#static-method-asyncresourcebindfn-type-thisarg">Static method: <code>AsyncResource.bind(fn[, type[, thisArg]])</code></a></li>
144<li><a href="#asyncresourcebindfn-thisarg"><code>asyncResource.bind(fn[, thisArg])</code></a></li>
145<li><a href="#asyncresourceruninasyncscopefn-thisarg-args"><code>asyncResource.runInAsyncScope(fn[, thisArg, ...args])</code></a></li>
146<li><a href="#asyncresourceemitdestroy"><code>asyncResource.emitDestroy()</code></a></li>
147<li><a href="#asyncresourceasyncid"><code>asyncResource.asyncId()</code></a></li>
148<li><a href="#asyncresourcetriggerasyncid"><code>asyncResource.triggerAsyncId()</code></a></li>
149<li><a href="#using-asyncresource-for-a-worker-thread-pool">Using <code>AsyncResource</code> for a <code>Worker</code> thread pool</a></li>
150<li><a href="#integrating-asyncresource-with-eventemitter">Integrating <code>AsyncResource</code> with <code>EventEmitter</code></a></li>
151</ul>
152</li>
153</ul>
154</li>
155</ul></div></div>
156    </li>
157
158
159    <li class="picker-header">
160      <a href="#">
161        <span class="collapsed-arrow">&#x25ba;</span><span class="expanded-arrow">&#x25bc;</span>
162        Index
163      </a>
164
165      <div class="picker"><ul>
166<li><a href="documentation.html" class="nav-documentation">About this documentation</a></li>
167<li><a href="synopsis.html" class="nav-synopsis">Usage and example</a></li>
168
169      <li>
170        <a href="index.html">Index</a>
171      </li>
172    </ul>
173
174<hr class="line">
175<ul>
176<li><a href="assert.html" class="nav-assert">Assertion testing</a></li>
177<li><a href="async_context.html" class="nav-async_context active">Asynchronous context tracking</a></li>
178<li><a href="async_hooks.html" class="nav-async_hooks">Async hooks</a></li>
179<li><a href="buffer.html" class="nav-buffer">Buffer</a></li>
180<li><a href="addons.html" class="nav-addons">C++ addons</a></li>
181<li><a href="n-api.html" class="nav-n-api">C/C++ addons with Node-API</a></li>
182<li><a href="embedding.html" class="nav-embedding">C++ embedder API</a></li>
183<li><a href="child_process.html" class="nav-child_process">Child processes</a></li>
184<li><a href="cluster.html" class="nav-cluster">Cluster</a></li>
185<li><a href="cli.html" class="nav-cli">Command-line options</a></li>
186<li><a href="console.html" class="nav-console">Console</a></li>
187<li><a href="corepack.html" class="nav-corepack">Corepack</a></li>
188<li><a href="crypto.html" class="nav-crypto">Crypto</a></li>
189<li><a href="debugger.html" class="nav-debugger">Debugger</a></li>
190<li><a href="deprecations.html" class="nav-deprecations">Deprecated APIs</a></li>
191<li><a href="diagnostics_channel.html" class="nav-diagnostics_channel">Diagnostics Channel</a></li>
192<li><a href="dns.html" class="nav-dns">DNS</a></li>
193<li><a href="domain.html" class="nav-domain">Domain</a></li>
194<li><a href="errors.html" class="nav-errors">Errors</a></li>
195<li><a href="events.html" class="nav-events">Events</a></li>
196<li><a href="fs.html" class="nav-fs">File system</a></li>
197<li><a href="globals.html" class="nav-globals">Globals</a></li>
198<li><a href="http.html" class="nav-http">HTTP</a></li>
199<li><a href="http2.html" class="nav-http2">HTTP/2</a></li>
200<li><a href="https.html" class="nav-https">HTTPS</a></li>
201<li><a href="inspector.html" class="nav-inspector">Inspector</a></li>
202<li><a href="intl.html" class="nav-intl">Internationalization</a></li>
203<li><a href="modules.html" class="nav-modules">Modules: CommonJS modules</a></li>
204<li><a href="esm.html" class="nav-esm">Modules: ECMAScript modules</a></li>
205<li><a href="module.html" class="nav-module">Modules: <code>node:module</code> API</a></li>
206<li><a href="packages.html" class="nav-packages">Modules: Packages</a></li>
207<li><a href="net.html" class="nav-net">Net</a></li>
208<li><a href="os.html" class="nav-os">OS</a></li>
209<li><a href="path.html" class="nav-path">Path</a></li>
210<li><a href="perf_hooks.html" class="nav-perf_hooks">Performance hooks</a></li>
211<li><a href="permissions.html" class="nav-permissions">Permissions</a></li>
212<li><a href="process.html" class="nav-process">Process</a></li>
213<li><a href="punycode.html" class="nav-punycode">Punycode</a></li>
214<li><a href="querystring.html" class="nav-querystring">Query strings</a></li>
215<li><a href="readline.html" class="nav-readline">Readline</a></li>
216<li><a href="repl.html" class="nav-repl">REPL</a></li>
217<li><a href="report.html" class="nav-report">Report</a></li>
218<li><a href="single-executable-applications.html" class="nav-single-executable-applications">Single executable applications</a></li>
219<li><a href="stream.html" class="nav-stream">Stream</a></li>
220<li><a href="string_decoder.html" class="nav-string_decoder">String decoder</a></li>
221<li><a href="test.html" class="nav-test">Test runner</a></li>
222<li><a href="timers.html" class="nav-timers">Timers</a></li>
223<li><a href="tls.html" class="nav-tls">TLS/SSL</a></li>
224<li><a href="tracing.html" class="nav-tracing">Trace events</a></li>
225<li><a href="tty.html" class="nav-tty">TTY</a></li>
226<li><a href="dgram.html" class="nav-dgram">UDP/datagram</a></li>
227<li><a href="url.html" class="nav-url">URL</a></li>
228<li><a href="util.html" class="nav-util">Utilities</a></li>
229<li><a href="v8.html" class="nav-v8">V8</a></li>
230<li><a href="vm.html" class="nav-vm">VM</a></li>
231<li><a href="wasi.html" class="nav-wasi">WASI</a></li>
232<li><a href="webcrypto.html" class="nav-webcrypto">Web Crypto API</a></li>
233<li><a href="webstreams.html" class="nav-webstreams">Web Streams API</a></li>
234<li><a href="worker_threads.html" class="nav-worker_threads">Worker threads</a></li>
235<li><a href="zlib.html" class="nav-zlib">Zlib</a></li>
236</ul>
237<hr class="line">
238<ul>
239<li><a href="https://github.com/nodejs/node" class="nav-https-github-com-nodejs-node">Code repository and issue tracker</a></li>
240</ul></div>
241    </li>
242
243
244    <li class="picker-header">
245      <a href="#">
246        <span class="collapsed-arrow">&#x25ba;</span><span class="expanded-arrow">&#x25bc;</span>
247        Other versions
248      </a>
249      <div class="picker"><ol id="alt-docs"><li><a href="https://nodejs.org/docs/latest-v21.x/api/async_context.html">21.x</a></li>
250<li><a href="https://nodejs.org/docs/latest-v20.x/api/async_context.html">20.x <b>LTS</b></a></li>
251<li><a href="https://nodejs.org/docs/latest-v19.x/api/async_context.html">19.x</a></li>
252<li><a href="https://nodejs.org/docs/latest-v18.x/api/async_context.html">18.x <b>LTS</b></a></li>
253<li><a href="https://nodejs.org/docs/latest-v17.x/api/async_context.html">17.x</a></li>
254<li><a href="https://nodejs.org/docs/latest-v16.x/api/async_context.html">16.x</a></li></ol></div>
255    </li>
256
257            <li class="picker-header">
258              <a href="#">
259                <span class="collapsed-arrow">&#x25ba;</span><span class="expanded-arrow">&#x25bc;</span>
260                Options
261              </a>
262
263              <div class="picker">
264                <ul>
265                  <li>
266                    <a href="all.html">View on single page</a>
267                  </li>
268                  <li>
269                    <a href="async_context.json">View as JSON</a>
270                  </li>
271                  <li class="edit_on_github"><a href="https://github.com/nodejs/node/edit/main/doc/api/async_context.md">Edit on GitHub</a></li>
272                </ul>
273              </div>
274            </li>
275          </ul>
276        </div>
277        <hr>
278      </header>
279
280      <details id="toc" open><summary>Table of contents</summary><ul>
281<li><span class="stability_2"><a href="#asynchronous-context-tracking">Asynchronous context tracking</a></span>
282<ul>
283<li><a href="#introduction">Introduction</a></li>
284<li><a href="#class-asynclocalstorage">Class: <code>AsyncLocalStorage</code></a>
285<ul>
286<li><a href="#new-asynclocalstorage"><code>new AsyncLocalStorage()</code></a></li>
287<li><span class="stability_1"><a href="#static-method-asynclocalstoragebindfn">Static method: <code>AsyncLocalStorage.bind(fn)</code></a></span></li>
288<li><span class="stability_1"><a href="#static-method-asynclocalstoragesnapshot">Static method: <code>AsyncLocalStorage.snapshot()</code></a></span></li>
289<li><span class="stability_1"><a href="#asynclocalstoragedisable"><code>asyncLocalStorage.disable()</code></a></span></li>
290<li><a href="#asynclocalstoragegetstore"><code>asyncLocalStorage.getStore()</code></a></li>
291<li><span class="stability_1"><a href="#asynclocalstorageenterwithstore"><code>asyncLocalStorage.enterWith(store)</code></a></span></li>
292<li><a href="#asynclocalstoragerunstore-callback-args"><code>asyncLocalStorage.run(store, callback[, ...args])</code></a></li>
293<li><span class="stability_1"><a href="#asynclocalstorageexitcallback-args"><code>asyncLocalStorage.exit(callback[, ...args])</code></a></span></li>
294<li><a href="#usage-with-asyncawait">Usage with <code>async/await</code></a></li>
295<li><a href="#troubleshooting-context-loss">Troubleshooting: Context loss</a></li>
296</ul>
297</li>
298<li><a href="#class-asyncresource">Class: <code>AsyncResource</code></a>
299<ul>
300<li><a href="#new-asyncresourcetype-options"><code>new AsyncResource(type[, options])</code></a></li>
301<li><a href="#static-method-asyncresourcebindfn-type-thisarg">Static method: <code>AsyncResource.bind(fn[, type[, thisArg]])</code></a></li>
302<li><a href="#asyncresourcebindfn-thisarg"><code>asyncResource.bind(fn[, thisArg])</code></a></li>
303<li><a href="#asyncresourceruninasyncscopefn-thisarg-args"><code>asyncResource.runInAsyncScope(fn[, thisArg, ...args])</code></a></li>
304<li><a href="#asyncresourceemitdestroy"><code>asyncResource.emitDestroy()</code></a></li>
305<li><a href="#asyncresourceasyncid"><code>asyncResource.asyncId()</code></a></li>
306<li><a href="#asyncresourcetriggerasyncid"><code>asyncResource.triggerAsyncId()</code></a></li>
307<li><a href="#using-asyncresource-for-a-worker-thread-pool">Using <code>AsyncResource</code> for a <code>Worker</code> thread pool</a></li>
308<li><a href="#integrating-asyncresource-with-eventemitter">Integrating <code>AsyncResource</code> with <code>EventEmitter</code></a></li>
309</ul>
310</li>
311</ul>
312</li>
313</ul></details>
314
315      <div id="apicontent">
316        <h2>Asynchronous context tracking<span><a class="mark" href="#asynchronous-context-tracking" id="asynchronous-context-tracking">#</a></span><a aria-hidden="true" class="legacy" id="async_context_asynchronous_context_tracking"></a></h2>
317
318<p></p><div class="api_stability api_stability_2"><a href="documentation.html#stability-index">Stability: 2</a> - Stable</div><p></p>
319<p><strong>Source Code:</strong> <a href="https://github.com/nodejs/node/blob/v18.20.1/lib/async_hooks.js">lib/async_hooks.js</a></p>
320<section><h3>Introduction<span><a class="mark" href="#introduction" id="introduction">#</a></span><a aria-hidden="true" class="legacy" id="async_context_introduction"></a></h3>
321<p>These classes are used to associate state and propagate it throughout
322callbacks and promise chains.
323They allow storing data throughout the lifetime of a web request
324or any other asynchronous duration. It is similar to thread-local storage
325in other languages.</p>
326<p>The <code>AsyncLocalStorage</code> and <code>AsyncResource</code> classes are part of the
327<code>node:async_hooks</code> module:</p>
328
329<pre class="with-73-chars"><input class="js-flavor-selector" type="checkbox" checked aria-label="Show modern ES modules syntax"><code class="language-js mjs"><span class="hljs-keyword">import</span> { <span class="hljs-title class_">AsyncLocalStorage</span>, <span class="hljs-title class_">AsyncResource</span> } <span class="hljs-keyword">from</span> <span class="hljs-string">'node:async_hooks'</span>;</code><code class="language-js cjs"><span class="hljs-keyword">const</span> { <span class="hljs-title class_">AsyncLocalStorage</span>, <span class="hljs-title class_">AsyncResource</span> } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'node:async_hooks'</span>);</code><button class="copy-button">copy</button></pre>
330</section><section><h3>Class: <code>AsyncLocalStorage</code><span><a class="mark" href="#class-asynclocalstorage" id="class-asynclocalstorage">#</a></span><a aria-hidden="true" class="legacy" id="async_context_class_asynclocalstorage"></a></h3>
331<div class="api_metadata">
332<details class="changelog"><summary>History</summary>
333<table>
334<tbody><tr><th>Version</th><th>Changes</th></tr>
335<tr><td>v16.4.0</td>
336<td><p>AsyncLocalStorage is now Stable. Previously, it had been Experimental.</p></td></tr>
337<tr><td>v13.10.0, v12.17.0</td>
338<td><p><span>Added in: v13.10.0, v12.17.0</span></p></td></tr>
339</tbody></table>
340</details>
341</div>
342<p>This class creates stores that stay coherent through asynchronous operations.</p>
343<p>While you can create your own implementation on top of the <code>node:async_hooks</code>
344module, <code>AsyncLocalStorage</code> should be preferred as it is a performant and memory
345safe implementation that involves significant optimizations that are non-obvious
346to implement.</p>
347<p>The following example uses <code>AsyncLocalStorage</code> to build a simple logger
348that assigns IDs to incoming HTTP requests and includes them in messages
349logged within each request.</p>
350
351<pre class="with-58-chars"><input class="js-flavor-selector" type="checkbox" checked aria-label="Show modern ES modules syntax"><code class="language-js mjs"><span class="hljs-keyword">import</span> http <span class="hljs-keyword">from</span> <span class="hljs-string">'node:http'</span>;
352<span class="hljs-keyword">import</span> { <span class="hljs-title class_">AsyncLocalStorage</span> } <span class="hljs-keyword">from</span> <span class="hljs-string">'node:async_hooks'</span>;
353
354<span class="hljs-keyword">const</span> asyncLocalStorage = <span class="hljs-keyword">new</span> <span class="hljs-title class_">AsyncLocalStorage</span>();
355
356<span class="hljs-keyword">function</span> <span class="hljs-title function_">logWithId</span>(<span class="hljs-params">msg</span>) {
357  <span class="hljs-keyword">const</span> id = asyncLocalStorage.<span class="hljs-title function_">getStore</span>();
358  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`<span class="hljs-subst">${id !== <span class="hljs-literal">undefined</span> ? id : <span class="hljs-string">'-'</span>}</span>:`</span>, msg);
359}
360
361<span class="hljs-keyword">let</span> idSeq = <span class="hljs-number">0</span>;
362http.<span class="hljs-title function_">createServer</span>(<span class="hljs-function">(<span class="hljs-params">req, res</span>) =></span> {
363  asyncLocalStorage.<span class="hljs-title function_">run</span>(idSeq++, <span class="hljs-function">() =></span> {
364    <span class="hljs-title function_">logWithId</span>(<span class="hljs-string">'start'</span>);
365    <span class="hljs-comment">// Imagine any chain of async operations here</span>
366    <span class="hljs-title function_">setImmediate</span>(<span class="hljs-function">() =></span> {
367      <span class="hljs-title function_">logWithId</span>(<span class="hljs-string">'finish'</span>);
368      res.<span class="hljs-title function_">end</span>();
369    });
370  });
371}).<span class="hljs-title function_">listen</span>(<span class="hljs-number">8080</span>);
372
373http.<span class="hljs-title function_">get</span>(<span class="hljs-string">'http://localhost:8080'</span>);
374http.<span class="hljs-title function_">get</span>(<span class="hljs-string">'http://localhost:8080'</span>);
375<span class="hljs-comment">// Prints:</span>
376<span class="hljs-comment">//   0: start</span>
377<span class="hljs-comment">//   1: start</span>
378<span class="hljs-comment">//   0: finish</span>
379<span class="hljs-comment">//   1: finish</span></code><code class="language-js cjs"><span class="hljs-keyword">const</span> http = <span class="hljs-built_in">require</span>(<span class="hljs-string">'node:http'</span>);
380<span class="hljs-keyword">const</span> { <span class="hljs-title class_">AsyncLocalStorage</span> } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'node:async_hooks'</span>);
381
382<span class="hljs-keyword">const</span> asyncLocalStorage = <span class="hljs-keyword">new</span> <span class="hljs-title class_">AsyncLocalStorage</span>();
383
384<span class="hljs-keyword">function</span> <span class="hljs-title function_">logWithId</span>(<span class="hljs-params">msg</span>) {
385  <span class="hljs-keyword">const</span> id = asyncLocalStorage.<span class="hljs-title function_">getStore</span>();
386  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">`<span class="hljs-subst">${id !== <span class="hljs-literal">undefined</span> ? id : <span class="hljs-string">'-'</span>}</span>:`</span>, msg);
387}
388
389<span class="hljs-keyword">let</span> idSeq = <span class="hljs-number">0</span>;
390http.<span class="hljs-title function_">createServer</span>(<span class="hljs-function">(<span class="hljs-params">req, res</span>) =></span> {
391  asyncLocalStorage.<span class="hljs-title function_">run</span>(idSeq++, <span class="hljs-function">() =></span> {
392    <span class="hljs-title function_">logWithId</span>(<span class="hljs-string">'start'</span>);
393    <span class="hljs-comment">// Imagine any chain of async operations here</span>
394    <span class="hljs-title function_">setImmediate</span>(<span class="hljs-function">() =></span> {
395      <span class="hljs-title function_">logWithId</span>(<span class="hljs-string">'finish'</span>);
396      res.<span class="hljs-title function_">end</span>();
397    });
398  });
399}).<span class="hljs-title function_">listen</span>(<span class="hljs-number">8080</span>);
400
401http.<span class="hljs-title function_">get</span>(<span class="hljs-string">'http://localhost:8080'</span>);
402http.<span class="hljs-title function_">get</span>(<span class="hljs-string">'http://localhost:8080'</span>);
403<span class="hljs-comment">// Prints:</span>
404<span class="hljs-comment">//   0: start</span>
405<span class="hljs-comment">//   1: start</span>
406<span class="hljs-comment">//   0: finish</span>
407<span class="hljs-comment">//   1: finish</span></code><button class="copy-button">copy</button></pre>
408<p>Each instance of <code>AsyncLocalStorage</code> maintains an independent storage context.
409Multiple instances can safely exist simultaneously without risk of interfering
410with each other's data.</p>
411<h4><code>new AsyncLocalStorage()</code><span><a class="mark" href="#new-asynclocalstorage" id="new-asynclocalstorage">#</a></span><a aria-hidden="true" class="legacy" id="async_context_new_asynclocalstorage"></a></h4>
412<div class="api_metadata">
413<details class="changelog"><summary>History</summary>
414<table>
415<tbody><tr><th>Version</th><th>Changes</th></tr>
416<tr><td>v18.16.0</td>
417<td><p>Removed experimental onPropagate option.</p></td></tr>
418<tr><td>v18.13.0</td>
419<td><p>Add option onPropagate.</p></td></tr>
420<tr><td>v13.10.0, v12.17.0</td>
421<td><p><span>Added in: v13.10.0, v12.17.0</span></p></td></tr>
422</tbody></table>
423</details>
424</div>
425<p>Creates a new instance of <code>AsyncLocalStorage</code>. Store is only provided within a
426<code>run()</code> call or after an <code>enterWith()</code> call.</p>
427<h4>Static method: <code>AsyncLocalStorage.bind(fn)</code><span><a class="mark" href="#static-method-asynclocalstoragebindfn" id="static-method-asynclocalstoragebindfn">#</a></span><a aria-hidden="true" class="legacy" id="async_context_static_method_asynclocalstorage_bind_fn"></a></h4>
428<div class="api_metadata">
429<span>Added in: v18.16.0</span>
430</div>
431<p></p><div class="api_stability api_stability_1"><a href="documentation.html#stability-index">Stability: 1</a> - Experimental</div><p></p>
432<ul>
433<li><code>fn</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function" class="type">&#x3C;Function></a> The function to bind to the current execution context.</li>
434<li>Returns: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function" class="type">&#x3C;Function></a> A new function that calls <code>fn</code> within the captured
435execution context.</li>
436</ul>
437<p>Binds the given function to the current execution context.</p>
438<h4>Static method: <code>AsyncLocalStorage.snapshot()</code><span><a class="mark" href="#static-method-asynclocalstoragesnapshot" id="static-method-asynclocalstoragesnapshot">#</a></span><a aria-hidden="true" class="legacy" id="async_context_static_method_asynclocalstorage_snapshot"></a></h4>
439<div class="api_metadata">
440<span>Added in: v18.16.0</span>
441</div>
442<p></p><div class="api_stability api_stability_1"><a href="documentation.html#stability-index">Stability: 1</a> - Experimental</div><p></p>
443<ul>
444<li>Returns: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function" class="type">&#x3C;Function></a> A new function with the signature
445<code>(fn: (...args) : R, ...args) : R</code>.</li>
446</ul>
447<p>Captures the current execution context and returns a function that accepts a
448function as an argument. Whenever the returned function is called, it
449calls the function passed to it within the captured context.</p>
450<pre><code class="language-js"><span class="hljs-keyword">const</span> asyncLocalStorage = <span class="hljs-keyword">new</span> <span class="hljs-title class_">AsyncLocalStorage</span>();
451<span class="hljs-keyword">const</span> runInAsyncScope = asyncLocalStorage.<span class="hljs-title function_">run</span>(<span class="hljs-number">123</span>, <span class="hljs-function">() =></span> <span class="hljs-title class_">AsyncLocalStorage</span>.<span class="hljs-title function_">snapshot</span>());
452<span class="hljs-keyword">const</span> result = asyncLocalStorage.<span class="hljs-title function_">run</span>(<span class="hljs-number">321</span>, <span class="hljs-function">() =></span> <span class="hljs-title function_">runInAsyncScope</span>(<span class="hljs-function">() =></span> asyncLocalStorage.<span class="hljs-title function_">getStore</span>()));
453<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(result);  <span class="hljs-comment">// returns 123</span></code> <button class="copy-button">copy</button></pre>
454<p>AsyncLocalStorage.snapshot() can replace the use of AsyncResource for simple
455async context tracking purposes, for example:</p>
456<pre><code class="language-js"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Foo</span> {
457  #runInAsyncScope = <span class="hljs-title class_">AsyncLocalStorage</span>.<span class="hljs-title function_">snapshot</span>();
458
459  <span class="hljs-title function_">get</span>(<span class="hljs-params"></span>) { <span class="hljs-keyword">return</span> <span class="hljs-variable language_">this</span>.#<span class="hljs-title function_">runInAsyncScope</span>(<span class="hljs-function">() =></span> asyncLocalStorage.<span class="hljs-title function_">getStore</span>()); }
460}
461
462<span class="hljs-keyword">const</span> foo = asyncLocalStorage.<span class="hljs-title function_">run</span>(<span class="hljs-number">123</span>, <span class="hljs-function">() =></span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Foo</span>());
463<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(asyncLocalStorage.<span class="hljs-title function_">run</span>(<span class="hljs-number">321</span>, <span class="hljs-function">() =></span> foo.<span class="hljs-title function_">get</span>())); <span class="hljs-comment">// returns 123</span></code> <button class="copy-button">copy</button></pre>
464<h4><code>asyncLocalStorage.disable()</code><span><a class="mark" href="#asynclocalstoragedisable" id="asynclocalstoragedisable">#</a></span><a aria-hidden="true" class="legacy" id="async_context_asynclocalstorage_disable"></a></h4>
465<div class="api_metadata">
466<span>Added in: v13.10.0, v12.17.0</span>
467</div>
468<p></p><div class="api_stability api_stability_1"><a href="documentation.html#stability-index">Stability: 1</a> - Experimental</div><p></p>
469<p>Disables the instance of <code>AsyncLocalStorage</code>. All subsequent calls
470to <code>asyncLocalStorage.getStore()</code> will return <code>undefined</code> until
471<code>asyncLocalStorage.run()</code> or <code>asyncLocalStorage.enterWith()</code> is called again.</p>
472<p>When calling <code>asyncLocalStorage.disable()</code>, all current contexts linked to the
473instance will be exited.</p>
474<p>Calling <code>asyncLocalStorage.disable()</code> is required before the
475<code>asyncLocalStorage</code> can be garbage collected. This does not apply to stores
476provided by the <code>asyncLocalStorage</code>, as those objects are garbage collected
477along with the corresponding async resources.</p>
478<p>Use this method when the <code>asyncLocalStorage</code> is not in use anymore
479in the current process.</p>
480<h4><code>asyncLocalStorage.getStore()</code><span><a class="mark" href="#asynclocalstoragegetstore" id="asynclocalstoragegetstore">#</a></span><a aria-hidden="true" class="legacy" id="async_context_asynclocalstorage_getstore"></a></h4>
481<div class="api_metadata">
482<span>Added in: v13.10.0, v12.17.0</span>
483</div>
484<ul>
485<li>Returns: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type">&#x3C;any></a></li>
486</ul>
487<p>Returns the current store.
488If called outside of an asynchronous context initialized by
489calling <code>asyncLocalStorage.run()</code> or <code>asyncLocalStorage.enterWith()</code>, it
490returns <code>undefined</code>.</p>
491<h4><code>asyncLocalStorage.enterWith(store)</code><span><a class="mark" href="#asynclocalstorageenterwithstore" id="asynclocalstorageenterwithstore">#</a></span><a aria-hidden="true" class="legacy" id="async_context_asynclocalstorage_enterwith_store"></a></h4>
492<div class="api_metadata">
493<span>Added in: v13.11.0, v12.17.0</span>
494</div>
495<p></p><div class="api_stability api_stability_1"><a href="documentation.html#stability-index">Stability: 1</a> - Experimental</div><p></p>
496<ul>
497<li><code>store</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type">&#x3C;any></a></li>
498</ul>
499<p>Transitions into the context for the remainder of the current
500synchronous execution and then persists the store through any following
501asynchronous calls.</p>
502<p>Example:</p>
503<pre><code class="language-js"><span class="hljs-keyword">const</span> store = { <span class="hljs-attr">id</span>: <span class="hljs-number">1</span> };
504<span class="hljs-comment">// Replaces previous store with the given store object</span>
505asyncLocalStorage.<span class="hljs-title function_">enterWith</span>(store);
506asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); <span class="hljs-comment">// Returns the store object</span>
507<span class="hljs-title function_">someAsyncOperation</span>(<span class="hljs-function">() =></span> {
508  asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); <span class="hljs-comment">// Returns the same object</span>
509});</code> <button class="copy-button">copy</button></pre>
510<p>This transition will continue for the <em>entire</em> synchronous execution.
511This means that if, for example, the context is entered within an event
512handler subsequent event handlers will also run within that context unless
513specifically bound to another context with an <code>AsyncResource</code>. That is why
514<code>run()</code> should be preferred over <code>enterWith()</code> unless there are strong reasons
515to use the latter method.</p>
516<pre><code class="language-js"><span class="hljs-keyword">const</span> store = { <span class="hljs-attr">id</span>: <span class="hljs-number">1</span> };
517
518emitter.<span class="hljs-title function_">on</span>(<span class="hljs-string">'my-event'</span>, <span class="hljs-function">() =></span> {
519  asyncLocalStorage.<span class="hljs-title function_">enterWith</span>(store);
520});
521emitter.<span class="hljs-title function_">on</span>(<span class="hljs-string">'my-event'</span>, <span class="hljs-function">() =></span> {
522  asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); <span class="hljs-comment">// Returns the same object</span>
523});
524
525asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); <span class="hljs-comment">// Returns undefined</span>
526emitter.<span class="hljs-title function_">emit</span>(<span class="hljs-string">'my-event'</span>);
527asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); <span class="hljs-comment">// Returns the same object</span></code> <button class="copy-button">copy</button></pre>
528<h4><code>asyncLocalStorage.run(store, callback[, ...args])</code><span><a class="mark" href="#asynclocalstoragerunstore-callback-args" id="asynclocalstoragerunstore-callback-args">#</a></span><a aria-hidden="true" class="legacy" id="async_context_asynclocalstorage_run_store_callback_args"></a></h4>
529<div class="api_metadata">
530<span>Added in: v13.10.0, v12.17.0</span>
531</div>
532<ul>
533<li><code>store</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type">&#x3C;any></a></li>
534<li><code>callback</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function" class="type">&#x3C;Function></a></li>
535<li><code>...args</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type">&#x3C;any></a></li>
536</ul>
537<p>Runs a function synchronously within a context and returns its
538return value. The store is not accessible outside of the callback function.
539The store is accessible to any asynchronous operations created within the
540callback.</p>
541<p>The optional <code>args</code> are passed to the callback function.</p>
542<p>If the callback function throws an error, the error is thrown by <code>run()</code> too.
543The stacktrace is not impacted by this call and the context is exited.</p>
544<p>Example:</p>
545<pre><code class="language-js"><span class="hljs-keyword">const</span> store = { <span class="hljs-attr">id</span>: <span class="hljs-number">2</span> };
546<span class="hljs-keyword">try</span> {
547  asyncLocalStorage.<span class="hljs-title function_">run</span>(store, <span class="hljs-function">() =></span> {
548    asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); <span class="hljs-comment">// Returns the store object</span>
549    <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> {
550      asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); <span class="hljs-comment">// Returns the store object</span>
551    }, <span class="hljs-number">200</span>);
552    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Error</span>();
553  });
554} <span class="hljs-keyword">catch</span> (e) {
555  asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); <span class="hljs-comment">// Returns undefined</span>
556  <span class="hljs-comment">// The error will be caught here</span>
557}</code> <button class="copy-button">copy</button></pre>
558<h4><code>asyncLocalStorage.exit(callback[, ...args])</code><span><a class="mark" href="#asynclocalstorageexitcallback-args" id="asynclocalstorageexitcallback-args">#</a></span><a aria-hidden="true" class="legacy" id="async_context_asynclocalstorage_exit_callback_args"></a></h4>
559<div class="api_metadata">
560<span>Added in: v13.10.0, v12.17.0</span>
561</div>
562<p></p><div class="api_stability api_stability_1"><a href="documentation.html#stability-index">Stability: 1</a> - Experimental</div><p></p>
563<ul>
564<li><code>callback</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function" class="type">&#x3C;Function></a></li>
565<li><code>...args</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type">&#x3C;any></a></li>
566</ul>
567<p>Runs a function synchronously outside of a context and returns its
568return value. The store is not accessible within the callback function or
569the asynchronous operations created within the callback. Any <code>getStore()</code>
570call done within the callback function will always return <code>undefined</code>.</p>
571<p>The optional <code>args</code> are passed to the callback function.</p>
572<p>If the callback function throws an error, the error is thrown by <code>exit()</code> too.
573The stacktrace is not impacted by this call and the context is re-entered.</p>
574<p>Example:</p>
575<pre><code class="language-js"><span class="hljs-comment">// Within a call to run</span>
576<span class="hljs-keyword">try</span> {
577  asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); <span class="hljs-comment">// Returns the store object or value</span>
578  asyncLocalStorage.<span class="hljs-title function_">exit</span>(<span class="hljs-function">() =></span> {
579    asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); <span class="hljs-comment">// Returns undefined</span>
580    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Error</span>();
581  });
582} <span class="hljs-keyword">catch</span> (e) {
583  asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); <span class="hljs-comment">// Returns the same object or value</span>
584  <span class="hljs-comment">// The error will be caught here</span>
585}</code> <button class="copy-button">copy</button></pre>
586<h4>Usage with <code>async/await</code><span><a class="mark" href="#usage-with-asyncawait" id="usage-with-asyncawait">#</a></span><a aria-hidden="true" class="legacy" id="async_context_usage_with_async_await"></a></h4>
587<p>If, within an async function, only one <code>await</code> call is to run within a context,
588the following pattern should be used:</p>
589<pre><code class="language-js"><span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">fn</span>(<span class="hljs-params"></span>) {
590  <span class="hljs-keyword">await</span> asyncLocalStorage.<span class="hljs-title function_">run</span>(<span class="hljs-keyword">new</span> <span class="hljs-title class_">Map</span>(), <span class="hljs-function">() =></span> {
591    asyncLocalStorage.<span class="hljs-title function_">getStore</span>().<span class="hljs-title function_">set</span>(<span class="hljs-string">'key'</span>, value);
592    <span class="hljs-keyword">return</span> <span class="hljs-title function_">foo</span>(); <span class="hljs-comment">// The return value of foo will be awaited</span>
593  });
594}</code> <button class="copy-button">copy</button></pre>
595<p>In this example, the store is only available in the callback function and the
596functions called by <code>foo</code>. Outside of <code>run</code>, calling <code>getStore</code> will return
597<code>undefined</code>.</p>
598<h4>Troubleshooting: Context loss<span><a class="mark" href="#troubleshooting-context-loss" id="troubleshooting-context-loss">#</a></span><a aria-hidden="true" class="legacy" id="async_context_troubleshooting_context_loss"></a></h4>
599<p>In most cases, <code>AsyncLocalStorage</code> works without issues. In rare situations, the
600current store is lost in one of the asynchronous operations.</p>
601<p>If your code is callback-based, it is enough to promisify it with
602<a href="util.html#utilpromisifyoriginal"><code>util.promisify()</code></a> so it starts working with native promises.</p>
603<p>If you need to use a callback-based API or your code assumes
604a custom thenable implementation, use the <a href="#class-asyncresource"><code>AsyncResource</code></a> class
605to associate the asynchronous operation with the correct execution context.
606Find the function call responsible for the context loss by logging the content
607of <code>asyncLocalStorage.getStore()</code> after the calls you suspect are responsible
608for the loss. When the code logs <code>undefined</code>, the last callback called is
609probably responsible for the context loss.</p>
610</section><section><h3>Class: <code>AsyncResource</code><span><a class="mark" href="#class-asyncresource" id="class-asyncresource">#</a></span><a aria-hidden="true" class="legacy" id="async_context_class_asyncresource"></a></h3>
611<div class="api_metadata">
612<details class="changelog"><summary>History</summary>
613<table>
614<tbody><tr><th>Version</th><th>Changes</th></tr>
615<tr><td>v16.4.0</td>
616<td><p>AsyncResource is now Stable. Previously, it had been Experimental.</p></td></tr>
617</tbody></table>
618</details>
619</div>
620<p>The class <code>AsyncResource</code> is designed to be extended by the embedder's async
621resources. Using this, users can easily trigger the lifetime events of their
622own resources.</p>
623<p>The <code>init</code> hook will trigger when an <code>AsyncResource</code> is instantiated.</p>
624<p>The following is an overview of the <code>AsyncResource</code> API.</p>
625
626<pre class="with-72-chars"><input class="js-flavor-selector" type="checkbox" checked aria-label="Show modern ES modules syntax"><code class="language-js mjs"><span class="hljs-keyword">import</span> { <span class="hljs-title class_">AsyncResource</span>, executionAsyncId } <span class="hljs-keyword">from</span> <span class="hljs-string">'node:async_hooks'</span>;
627
628<span class="hljs-comment">// AsyncResource() is meant to be extended. Instantiating a</span>
629<span class="hljs-comment">// new AsyncResource() also triggers init. If triggerAsyncId is omitted then</span>
630<span class="hljs-comment">// async_hook.executionAsyncId() is used.</span>
631<span class="hljs-keyword">const</span> asyncResource = <span class="hljs-keyword">new</span> <span class="hljs-title class_">AsyncResource</span>(
632  type, { <span class="hljs-attr">triggerAsyncId</span>: <span class="hljs-title function_">executionAsyncId</span>(), <span class="hljs-attr">requireManualDestroy</span>: <span class="hljs-literal">false</span> },
633);
634
635<span class="hljs-comment">// Run a function in the execution context of the resource. This will</span>
636<span class="hljs-comment">// * establish the context of the resource</span>
637<span class="hljs-comment">// * trigger the AsyncHooks before callbacks</span>
638<span class="hljs-comment">// * call the provided function `fn` with the supplied arguments</span>
639<span class="hljs-comment">// * trigger the AsyncHooks after callbacks</span>
640<span class="hljs-comment">// * restore the original execution context</span>
641asyncResource.<span class="hljs-title function_">runInAsyncScope</span>(fn, thisArg, ...args);
642
643<span class="hljs-comment">// Call AsyncHooks destroy callbacks.</span>
644asyncResource.<span class="hljs-title function_">emitDestroy</span>();
645
646<span class="hljs-comment">// Return the unique ID assigned to the AsyncResource instance.</span>
647asyncResource.<span class="hljs-title function_">asyncId</span>();
648
649<span class="hljs-comment">// Return the trigger ID for the AsyncResource instance.</span>
650asyncResource.<span class="hljs-title function_">triggerAsyncId</span>();</code><code class="language-js cjs"><span class="hljs-keyword">const</span> { <span class="hljs-title class_">AsyncResource</span>, executionAsyncId } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'node:async_hooks'</span>);
651
652<span class="hljs-comment">// AsyncResource() is meant to be extended. Instantiating a</span>
653<span class="hljs-comment">// new AsyncResource() also triggers init. If triggerAsyncId is omitted then</span>
654<span class="hljs-comment">// async_hook.executionAsyncId() is used.</span>
655<span class="hljs-keyword">const</span> asyncResource = <span class="hljs-keyword">new</span> <span class="hljs-title class_">AsyncResource</span>(
656  type, { <span class="hljs-attr">triggerAsyncId</span>: <span class="hljs-title function_">executionAsyncId</span>(), <span class="hljs-attr">requireManualDestroy</span>: <span class="hljs-literal">false</span> },
657);
658
659<span class="hljs-comment">// Run a function in the execution context of the resource. This will</span>
660<span class="hljs-comment">// * establish the context of the resource</span>
661<span class="hljs-comment">// * trigger the AsyncHooks before callbacks</span>
662<span class="hljs-comment">// * call the provided function `fn` with the supplied arguments</span>
663<span class="hljs-comment">// * trigger the AsyncHooks after callbacks</span>
664<span class="hljs-comment">// * restore the original execution context</span>
665asyncResource.<span class="hljs-title function_">runInAsyncScope</span>(fn, thisArg, ...args);
666
667<span class="hljs-comment">// Call AsyncHooks destroy callbacks.</span>
668asyncResource.<span class="hljs-title function_">emitDestroy</span>();
669
670<span class="hljs-comment">// Return the unique ID assigned to the AsyncResource instance.</span>
671asyncResource.<span class="hljs-title function_">asyncId</span>();
672
673<span class="hljs-comment">// Return the trigger ID for the AsyncResource instance.</span>
674asyncResource.<span class="hljs-title function_">triggerAsyncId</span>();</code><button class="copy-button">copy</button></pre>
675<h4><code>new AsyncResource(type[, options])</code><span><a class="mark" href="#new-asyncresourcetype-options" id="new-asyncresourcetype-options">#</a></span><a aria-hidden="true" class="legacy" id="async_context_new_asyncresource_type_options"></a></h4>
676<ul>
677<li><code>type</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type" class="type">&#x3C;string></a> The type of async event.</li>
678<li><code>options</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object" class="type">&#x3C;Object></a>
679<ul>
680<li><code>triggerAsyncId</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type" class="type">&#x3C;number></a> The ID of the execution context that created this
681async event. <strong>Default:</strong> <code>executionAsyncId()</code>.</li>
682<li><code>requireManualDestroy</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Boolean_type" class="type">&#x3C;boolean></a> If set to <code>true</code>, disables <code>emitDestroy</code>
683when the object is garbage collected. This usually does not need to be set
684(even if <code>emitDestroy</code> is called manually), unless the resource's <code>asyncId</code>
685is retrieved and the sensitive API's <code>emitDestroy</code> is called with it.
686When set to <code>false</code>, the <code>emitDestroy</code> call on garbage collection
687will only take place if there is at least one active <code>destroy</code> hook.
688<strong>Default:</strong> <code>false</code>.</li>
689</ul>
690</li>
691</ul>
692<p>Example usage:</p>
693<pre><code class="language-js"><span class="hljs-keyword">class</span> <span class="hljs-title class_">DBQuery</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_ inherited__">AsyncResource</span> {
694  <span class="hljs-title function_">constructor</span>(<span class="hljs-params">db</span>) {
695    <span class="hljs-variable language_">super</span>(<span class="hljs-string">'DBQuery'</span>);
696    <span class="hljs-variable language_">this</span>.<span class="hljs-property">db</span> = db;
697  }
698
699  <span class="hljs-title function_">getInfo</span>(<span class="hljs-params">query, callback</span>) {
700    <span class="hljs-variable language_">this</span>.<span class="hljs-property">db</span>.<span class="hljs-title function_">get</span>(query, <span class="hljs-function">(<span class="hljs-params">err, data</span>) =></span> {
701      <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">runInAsyncScope</span>(callback, <span class="hljs-literal">null</span>, err, data);
702    });
703  }
704
705  <span class="hljs-title function_">close</span>(<span class="hljs-params"></span>) {
706    <span class="hljs-variable language_">this</span>.<span class="hljs-property">db</span> = <span class="hljs-literal">null</span>;
707    <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">emitDestroy</span>();
708  }
709}</code> <button class="copy-button">copy</button></pre>
710<h4>Static method: <code>AsyncResource.bind(fn[, type[, thisArg]])</code><span><a class="mark" href="#static-method-asyncresourcebindfn-type-thisarg" id="static-method-asyncresourcebindfn-type-thisarg">#</a></span><a aria-hidden="true" class="legacy" id="async_context_static_method_asyncresource_bind_fn_type_thisarg"></a></h4>
711<div class="api_metadata">
712<details class="changelog"><summary>History</summary>
713<table>
714<tbody><tr><th>Version</th><th>Changes</th></tr>
715<tr><td>v17.8.0</td>
716<td><p>Changed the default when <code>thisArg</code> is undefined to use <code>this</code> from the caller.</p></td></tr>
717<tr><td>v16.0.0</td>
718<td><p>Added optional thisArg.</p></td></tr>
719<tr><td>v14.8.0, v12.19.0</td>
720<td><p><span>Added in: v14.8.0, v12.19.0</span></p></td></tr>
721</tbody></table>
722</details>
723</div>
724<ul>
725<li><code>fn</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function" class="type">&#x3C;Function></a> The function to bind to the current execution context.</li>
726<li><code>type</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type" class="type">&#x3C;string></a> An optional name to associate with the underlying
727<code>AsyncResource</code>.</li>
728<li><code>thisArg</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type">&#x3C;any></a></li>
729</ul>
730<p>Binds the given function to the current execution context.</p>
731<p>The returned function will have an <code>asyncResource</code> property referencing
732the <code>AsyncResource</code> to which the function is bound.</p>
733<h4><code>asyncResource.bind(fn[, thisArg])</code><span><a class="mark" href="#asyncresourcebindfn-thisarg" id="asyncresourcebindfn-thisarg">#</a></span><a aria-hidden="true" class="legacy" id="async_context_asyncresource_bind_fn_thisarg"></a></h4>
734<div class="api_metadata">
735<details class="changelog"><summary>History</summary>
736<table>
737<tbody><tr><th>Version</th><th>Changes</th></tr>
738<tr><td>v17.8.0</td>
739<td><p>Changed the default when <code>thisArg</code> is undefined to use <code>this</code> from the caller.</p></td></tr>
740<tr><td>v16.0.0</td>
741<td><p>Added optional thisArg.</p></td></tr>
742<tr><td>v14.8.0, v12.19.0</td>
743<td><p><span>Added in: v14.8.0, v12.19.0</span></p></td></tr>
744</tbody></table>
745</details>
746</div>
747<ul>
748<li><code>fn</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function" class="type">&#x3C;Function></a> The function to bind to the current <code>AsyncResource</code>.</li>
749<li><code>thisArg</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type">&#x3C;any></a></li>
750</ul>
751<p>Binds the given function to execute to this <code>AsyncResource</code>'s scope.</p>
752<p>The returned function will have an <code>asyncResource</code> property referencing
753the <code>AsyncResource</code> to which the function is bound.</p>
754<h4><code>asyncResource.runInAsyncScope(fn[, thisArg, ...args])</code><span><a class="mark" href="#asyncresourceruninasyncscopefn-thisarg-args" id="asyncresourceruninasyncscopefn-thisarg-args">#</a></span><a aria-hidden="true" class="legacy" id="async_context_asyncresource_runinasyncscope_fn_thisarg_args"></a></h4>
755<div class="api_metadata">
756<span>Added in: v9.6.0</span>
757</div>
758<ul>
759<li><code>fn</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function" class="type">&#x3C;Function></a> The function to call in the execution context of this async
760resource.</li>
761<li><code>thisArg</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type">&#x3C;any></a> The receiver to be used for the function call.</li>
762<li><code>...args</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type">&#x3C;any></a> Optional arguments to pass to the function.</li>
763</ul>
764<p>Call the provided function with the provided arguments in the execution context
765of the async resource. This will establish the context, trigger the AsyncHooks
766before callbacks, call the function, trigger the AsyncHooks after callbacks, and
767then restore the original execution context.</p>
768<h4><code>asyncResource.emitDestroy()</code><span><a class="mark" href="#asyncresourceemitdestroy" id="asyncresourceemitdestroy">#</a></span><a aria-hidden="true" class="legacy" id="async_context_asyncresource_emitdestroy"></a></h4>
769<ul>
770<li>Returns: <a href="async_hooks.html#class-asyncresource" class="type">&#x3C;AsyncResource></a> A reference to <code>asyncResource</code>.</li>
771</ul>
772<p>Call all <code>destroy</code> hooks. This should only ever be called once. An error will
773be thrown if it is called more than once. This <strong>must</strong> be manually called. If
774the resource is left to be collected by the GC then the <code>destroy</code> hooks will
775never be called.</p>
776<h4><code>asyncResource.asyncId()</code><span><a class="mark" href="#asyncresourceasyncid" id="asyncresourceasyncid">#</a></span><a aria-hidden="true" class="legacy" id="async_context_asyncresource_asyncid"></a></h4>
777<ul>
778<li>Returns: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type" class="type">&#x3C;number></a> The unique <code>asyncId</code> assigned to the resource.</li>
779</ul>
780<h4><code>asyncResource.triggerAsyncId()</code><span><a class="mark" href="#asyncresourcetriggerasyncid" id="asyncresourcetriggerasyncid">#</a></span><a aria-hidden="true" class="legacy" id="async_context_asyncresource_triggerasyncid"></a></h4>
781<ul>
782<li>Returns: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type" class="type">&#x3C;number></a> The same <code>triggerAsyncId</code> that is passed to the
783<code>AsyncResource</code> constructor.</li>
784</ul>
785<p><a id="async-resource-worker-pool"></a></p>
786<h4>Using <code>AsyncResource</code> for a <code>Worker</code> thread pool<span><a class="mark" href="#using-asyncresource-for-a-worker-thread-pool" id="using-asyncresource-for-a-worker-thread-pool">#</a></span><a aria-hidden="true" class="legacy" id="async_context_using_asyncresource_for_a_worker_thread_pool"></a></h4>
787<p>The following example shows how to use the <code>AsyncResource</code> class to properly
788provide async tracking for a <a href="worker_threads.html#class-worker"><code>Worker</code></a> pool. Other resource pools, such as
789database connection pools, can follow a similar model.</p>
790<p>Assuming that the task is adding two numbers, using a file named
791<code>task_processor.js</code> with the following content:</p>
792
793<pre class="with-54-chars"><input class="js-flavor-selector" type="checkbox" checked aria-label="Show modern ES modules syntax"><code class="language-js mjs"><span class="hljs-keyword">import</span> { parentPort } <span class="hljs-keyword">from</span> <span class="hljs-string">'node:worker_threads'</span>;
794parentPort.<span class="hljs-title function_">on</span>(<span class="hljs-string">'message'</span>, <span class="hljs-function">(<span class="hljs-params">task</span>) =></span> {
795  parentPort.<span class="hljs-title function_">postMessage</span>(task.<span class="hljs-property">a</span> + task.<span class="hljs-property">b</span>);
796});</code><code class="language-js cjs"><span class="hljs-keyword">const</span> { parentPort } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'node:worker_threads'</span>);
797parentPort.<span class="hljs-title function_">on</span>(<span class="hljs-string">'message'</span>, <span class="hljs-function">(<span class="hljs-params">task</span>) =></span> {
798  parentPort.<span class="hljs-title function_">postMessage</span>(task.<span class="hljs-property">a</span> + task.<span class="hljs-property">b</span>);
799});</code><button class="copy-button">copy</button></pre>
800<p>a Worker pool around it could use the following structure:</p>
801
802<pre class="with-54-chars"><input class="js-flavor-selector" type="checkbox" checked aria-label="Show modern ES modules syntax"><code class="language-js mjs"><span class="hljs-keyword">import</span> { <span class="hljs-title class_">AsyncResource</span> } <span class="hljs-keyword">from</span> <span class="hljs-string">'node:async_hooks'</span>;
803<span class="hljs-keyword">import</span> { <span class="hljs-title class_">EventEmitter</span> } <span class="hljs-keyword">from</span> <span class="hljs-string">'node:events'</span>;
804<span class="hljs-keyword">import</span> path <span class="hljs-keyword">from</span> <span class="hljs-string">'node:path'</span>;
805<span class="hljs-keyword">import</span> { <span class="hljs-title class_">Worker</span> } <span class="hljs-keyword">from</span> <span class="hljs-string">'node:worker_threads'</span>;
806
807<span class="hljs-keyword">const</span> kTaskInfo = <span class="hljs-title class_">Symbol</span>(<span class="hljs-string">'kTaskInfo'</span>);
808<span class="hljs-keyword">const</span> kWorkerFreedEvent = <span class="hljs-title class_">Symbol</span>(<span class="hljs-string">'kWorkerFreedEvent'</span>);
809
810<span class="hljs-keyword">class</span> <span class="hljs-title class_">WorkerPoolTaskInfo</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_ inherited__">AsyncResource</span> {
811  <span class="hljs-title function_">constructor</span>(<span class="hljs-params">callback</span>) {
812    <span class="hljs-variable language_">super</span>(<span class="hljs-string">'WorkerPoolTaskInfo'</span>);
813    <span class="hljs-variable language_">this</span>.<span class="hljs-property">callback</span> = callback;
814  }
815
816  <span class="hljs-title function_">done</span>(<span class="hljs-params">err, result</span>) {
817    <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">runInAsyncScope</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">callback</span>, <span class="hljs-literal">null</span>, err, result);
818    <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">emitDestroy</span>();  <span class="hljs-comment">// `TaskInfo`s are used only once.</span>
819  }
820}
821
822<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">WorkerPool</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_ inherited__">EventEmitter</span> {
823  <span class="hljs-title function_">constructor</span>(<span class="hljs-params">numThreads</span>) {
824    <span class="hljs-variable language_">super</span>();
825    <span class="hljs-variable language_">this</span>.<span class="hljs-property">numThreads</span> = numThreads;
826    <span class="hljs-variable language_">this</span>.<span class="hljs-property">workers</span> = [];
827    <span class="hljs-variable language_">this</span>.<span class="hljs-property">freeWorkers</span> = [];
828    <span class="hljs-variable language_">this</span>.<span class="hljs-property">tasks</span> = [];
829
830    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &#x3C; numThreads; i++)
831      <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">addNewWorker</span>();
832
833    <span class="hljs-comment">// Any time the kWorkerFreedEvent is emitted, dispatch</span>
834    <span class="hljs-comment">// the next task pending in the queue, if any.</span>
835    <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">on</span>(kWorkerFreedEvent, <span class="hljs-function">() =></span> {
836      <span class="hljs-keyword">if</span> (<span class="hljs-variable language_">this</span>.<span class="hljs-property">tasks</span>.<span class="hljs-property">length</span> > <span class="hljs-number">0</span>) {
837        <span class="hljs-keyword">const</span> { task, callback } = <span class="hljs-variable language_">this</span>.<span class="hljs-property">tasks</span>.<span class="hljs-title function_">shift</span>();
838        <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">runTask</span>(task, callback);
839      }
840    });
841  }
842
843  <span class="hljs-title function_">addNewWorker</span>(<span class="hljs-params"></span>) {
844    <span class="hljs-keyword">const</span> worker = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Worker</span>(<span class="hljs-keyword">new</span> <span class="hljs-title function_">URL</span>(<span class="hljs-string">'task_processor.js'</span>, <span class="hljs-keyword">import</span>.<span class="hljs-property">meta</span>.<span class="hljs-property">url</span>));
845    worker.<span class="hljs-title function_">on</span>(<span class="hljs-string">'message'</span>, <span class="hljs-function">(<span class="hljs-params">result</span>) =></span> {
846      <span class="hljs-comment">// In case of success: Call the callback that was passed to `runTask`,</span>
847      <span class="hljs-comment">// remove the `TaskInfo` associated with the Worker, and mark it as free</span>
848      <span class="hljs-comment">// again.</span>
849      worker[kTaskInfo].<span class="hljs-title function_">done</span>(<span class="hljs-literal">null</span>, result);
850      worker[kTaskInfo] = <span class="hljs-literal">null</span>;
851      <span class="hljs-variable language_">this</span>.<span class="hljs-property">freeWorkers</span>.<span class="hljs-title function_">push</span>(worker);
852      <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">emit</span>(kWorkerFreedEvent);
853    });
854    worker.<span class="hljs-title function_">on</span>(<span class="hljs-string">'error'</span>, <span class="hljs-function">(<span class="hljs-params">err</span>) =></span> {
855      <span class="hljs-comment">// In case of an uncaught exception: Call the callback that was passed to</span>
856      <span class="hljs-comment">// `runTask` with the error.</span>
857      <span class="hljs-keyword">if</span> (worker[kTaskInfo])
858        worker[kTaskInfo].<span class="hljs-title function_">done</span>(err, <span class="hljs-literal">null</span>);
859      <span class="hljs-keyword">else</span>
860        <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">emit</span>(<span class="hljs-string">'error'</span>, err);
861      <span class="hljs-comment">// Remove the worker from the list and start a new Worker to replace the</span>
862      <span class="hljs-comment">// current one.</span>
863      <span class="hljs-variable language_">this</span>.<span class="hljs-property">workers</span>.<span class="hljs-title function_">splice</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">workers</span>.<span class="hljs-title function_">indexOf</span>(worker), <span class="hljs-number">1</span>);
864      <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">addNewWorker</span>();
865    });
866    <span class="hljs-variable language_">this</span>.<span class="hljs-property">workers</span>.<span class="hljs-title function_">push</span>(worker);
867    <span class="hljs-variable language_">this</span>.<span class="hljs-property">freeWorkers</span>.<span class="hljs-title function_">push</span>(worker);
868    <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">emit</span>(kWorkerFreedEvent);
869  }
870
871  <span class="hljs-title function_">runTask</span>(<span class="hljs-params">task, callback</span>) {
872    <span class="hljs-keyword">if</span> (<span class="hljs-variable language_">this</span>.<span class="hljs-property">freeWorkers</span>.<span class="hljs-property">length</span> === <span class="hljs-number">0</span>) {
873      <span class="hljs-comment">// No free threads, wait until a worker thread becomes free.</span>
874      <span class="hljs-variable language_">this</span>.<span class="hljs-property">tasks</span>.<span class="hljs-title function_">push</span>({ task, callback });
875      <span class="hljs-keyword">return</span>;
876    }
877
878    <span class="hljs-keyword">const</span> worker = <span class="hljs-variable language_">this</span>.<span class="hljs-property">freeWorkers</span>.<span class="hljs-title function_">pop</span>();
879    worker[kTaskInfo] = <span class="hljs-keyword">new</span> <span class="hljs-title class_">WorkerPoolTaskInfo</span>(callback);
880    worker.<span class="hljs-title function_">postMessage</span>(task);
881  }
882
883  <span class="hljs-title function_">close</span>(<span class="hljs-params"></span>) {
884    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> worker <span class="hljs-keyword">of</span> <span class="hljs-variable language_">this</span>.<span class="hljs-property">workers</span>) worker.<span class="hljs-title function_">terminate</span>();
885  }
886}</code><code class="language-js cjs"><span class="hljs-keyword">const</span> { <span class="hljs-title class_">AsyncResource</span> } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'node:async_hooks'</span>);
887<span class="hljs-keyword">const</span> { <span class="hljs-title class_">EventEmitter</span> } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'node:events'</span>);
888<span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">'node:path'</span>);
889<span class="hljs-keyword">const</span> { <span class="hljs-title class_">Worker</span> } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'node:worker_threads'</span>);
890
891<span class="hljs-keyword">const</span> kTaskInfo = <span class="hljs-title class_">Symbol</span>(<span class="hljs-string">'kTaskInfo'</span>);
892<span class="hljs-keyword">const</span> kWorkerFreedEvent = <span class="hljs-title class_">Symbol</span>(<span class="hljs-string">'kWorkerFreedEvent'</span>);
893
894<span class="hljs-keyword">class</span> <span class="hljs-title class_">WorkerPoolTaskInfo</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_ inherited__">AsyncResource</span> {
895  <span class="hljs-title function_">constructor</span>(<span class="hljs-params">callback</span>) {
896    <span class="hljs-variable language_">super</span>(<span class="hljs-string">'WorkerPoolTaskInfo'</span>);
897    <span class="hljs-variable language_">this</span>.<span class="hljs-property">callback</span> = callback;
898  }
899
900  <span class="hljs-title function_">done</span>(<span class="hljs-params">err, result</span>) {
901    <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">runInAsyncScope</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">callback</span>, <span class="hljs-literal">null</span>, err, result);
902    <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">emitDestroy</span>();  <span class="hljs-comment">// `TaskInfo`s are used only once.</span>
903  }
904}
905
906<span class="hljs-keyword">class</span> <span class="hljs-title class_">WorkerPool</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_ inherited__">EventEmitter</span> {
907  <span class="hljs-title function_">constructor</span>(<span class="hljs-params">numThreads</span>) {
908    <span class="hljs-variable language_">super</span>();
909    <span class="hljs-variable language_">this</span>.<span class="hljs-property">numThreads</span> = numThreads;
910    <span class="hljs-variable language_">this</span>.<span class="hljs-property">workers</span> = [];
911    <span class="hljs-variable language_">this</span>.<span class="hljs-property">freeWorkers</span> = [];
912    <span class="hljs-variable language_">this</span>.<span class="hljs-property">tasks</span> = [];
913
914    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &#x3C; numThreads; i++)
915      <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">addNewWorker</span>();
916
917    <span class="hljs-comment">// Any time the kWorkerFreedEvent is emitted, dispatch</span>
918    <span class="hljs-comment">// the next task pending in the queue, if any.</span>
919    <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">on</span>(kWorkerFreedEvent, <span class="hljs-function">() =></span> {
920      <span class="hljs-keyword">if</span> (<span class="hljs-variable language_">this</span>.<span class="hljs-property">tasks</span>.<span class="hljs-property">length</span> > <span class="hljs-number">0</span>) {
921        <span class="hljs-keyword">const</span> { task, callback } = <span class="hljs-variable language_">this</span>.<span class="hljs-property">tasks</span>.<span class="hljs-title function_">shift</span>();
922        <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">runTask</span>(task, callback);
923      }
924    });
925  }
926
927  <span class="hljs-title function_">addNewWorker</span>(<span class="hljs-params"></span>) {
928    <span class="hljs-keyword">const</span> worker = <span class="hljs-keyword">new</span> <span class="hljs-title class_">Worker</span>(path.<span class="hljs-title function_">resolve</span>(__dirname, <span class="hljs-string">'task_processor.js'</span>));
929    worker.<span class="hljs-title function_">on</span>(<span class="hljs-string">'message'</span>, <span class="hljs-function">(<span class="hljs-params">result</span>) =></span> {
930      <span class="hljs-comment">// In case of success: Call the callback that was passed to `runTask`,</span>
931      <span class="hljs-comment">// remove the `TaskInfo` associated with the Worker, and mark it as free</span>
932      <span class="hljs-comment">// again.</span>
933      worker[kTaskInfo].<span class="hljs-title function_">done</span>(<span class="hljs-literal">null</span>, result);
934      worker[kTaskInfo] = <span class="hljs-literal">null</span>;
935      <span class="hljs-variable language_">this</span>.<span class="hljs-property">freeWorkers</span>.<span class="hljs-title function_">push</span>(worker);
936      <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">emit</span>(kWorkerFreedEvent);
937    });
938    worker.<span class="hljs-title function_">on</span>(<span class="hljs-string">'error'</span>, <span class="hljs-function">(<span class="hljs-params">err</span>) =></span> {
939      <span class="hljs-comment">// In case of an uncaught exception: Call the callback that was passed to</span>
940      <span class="hljs-comment">// `runTask` with the error.</span>
941      <span class="hljs-keyword">if</span> (worker[kTaskInfo])
942        worker[kTaskInfo].<span class="hljs-title function_">done</span>(err, <span class="hljs-literal">null</span>);
943      <span class="hljs-keyword">else</span>
944        <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">emit</span>(<span class="hljs-string">'error'</span>, err);
945      <span class="hljs-comment">// Remove the worker from the list and start a new Worker to replace the</span>
946      <span class="hljs-comment">// current one.</span>
947      <span class="hljs-variable language_">this</span>.<span class="hljs-property">workers</span>.<span class="hljs-title function_">splice</span>(<span class="hljs-variable language_">this</span>.<span class="hljs-property">workers</span>.<span class="hljs-title function_">indexOf</span>(worker), <span class="hljs-number">1</span>);
948      <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">addNewWorker</span>();
949    });
950    <span class="hljs-variable language_">this</span>.<span class="hljs-property">workers</span>.<span class="hljs-title function_">push</span>(worker);
951    <span class="hljs-variable language_">this</span>.<span class="hljs-property">freeWorkers</span>.<span class="hljs-title function_">push</span>(worker);
952    <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">emit</span>(kWorkerFreedEvent);
953  }
954
955  <span class="hljs-title function_">runTask</span>(<span class="hljs-params">task, callback</span>) {
956    <span class="hljs-keyword">if</span> (<span class="hljs-variable language_">this</span>.<span class="hljs-property">freeWorkers</span>.<span class="hljs-property">length</span> === <span class="hljs-number">0</span>) {
957      <span class="hljs-comment">// No free threads, wait until a worker thread becomes free.</span>
958      <span class="hljs-variable language_">this</span>.<span class="hljs-property">tasks</span>.<span class="hljs-title function_">push</span>({ task, callback });
959      <span class="hljs-keyword">return</span>;
960    }
961
962    <span class="hljs-keyword">const</span> worker = <span class="hljs-variable language_">this</span>.<span class="hljs-property">freeWorkers</span>.<span class="hljs-title function_">pop</span>();
963    worker[kTaskInfo] = <span class="hljs-keyword">new</span> <span class="hljs-title class_">WorkerPoolTaskInfo</span>(callback);
964    worker.<span class="hljs-title function_">postMessage</span>(task);
965  }
966
967  <span class="hljs-title function_">close</span>(<span class="hljs-params"></span>) {
968    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> worker <span class="hljs-keyword">of</span> <span class="hljs-variable language_">this</span>.<span class="hljs-property">workers</span>) worker.<span class="hljs-title function_">terminate</span>();
969  }
970}
971
972<span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = <span class="hljs-title class_">WorkerPool</span>;</code><button class="copy-button">copy</button></pre>
973<p>Without the explicit tracking added by the <code>WorkerPoolTaskInfo</code> objects,
974it would appear that the callbacks are associated with the individual <code>Worker</code>
975objects. However, the creation of the <code>Worker</code>s is not associated with the
976creation of the tasks and does not provide information about when tasks
977were scheduled.</p>
978<p>This pool could be used as follows:</p>
979
980<pre class="with-47-chars"><input class="js-flavor-selector" type="checkbox" checked aria-label="Show modern ES modules syntax"><code class="language-js mjs"><span class="hljs-keyword">import</span> <span class="hljs-title class_">WorkerPool</span> <span class="hljs-keyword">from</span> <span class="hljs-string">'./worker_pool.js'</span>;
981<span class="hljs-keyword">import</span> os <span class="hljs-keyword">from</span> <span class="hljs-string">'node:os'</span>;
982
983<span class="hljs-keyword">const</span> pool = <span class="hljs-keyword">new</span> <span class="hljs-title class_">WorkerPool</span>(os.<span class="hljs-title function_">availableParallelism</span>());
984
985<span class="hljs-keyword">let</span> finished = <span class="hljs-number">0</span>;
986<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &#x3C; <span class="hljs-number">10</span>; i++) {
987  pool.<span class="hljs-title function_">runTask</span>({ <span class="hljs-attr">a</span>: <span class="hljs-number">42</span>, <span class="hljs-attr">b</span>: <span class="hljs-number">100</span> }, <span class="hljs-function">(<span class="hljs-params">err, result</span>) =></span> {
988    <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(i, err, result);
989    <span class="hljs-keyword">if</span> (++finished === <span class="hljs-number">10</span>)
990      pool.<span class="hljs-title function_">close</span>();
991  });
992}</code><code class="language-js cjs"><span class="hljs-keyword">const</span> <span class="hljs-title class_">WorkerPool</span> = <span class="hljs-built_in">require</span>(<span class="hljs-string">'./worker_pool.js'</span>);
993<span class="hljs-keyword">const</span> os = <span class="hljs-built_in">require</span>(<span class="hljs-string">'node:os'</span>);
994
995<span class="hljs-keyword">const</span> pool = <span class="hljs-keyword">new</span> <span class="hljs-title class_">WorkerPool</span>(os.<span class="hljs-title function_">availableParallelism</span>());
996
997<span class="hljs-keyword">let</span> finished = <span class="hljs-number">0</span>;
998<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &#x3C; <span class="hljs-number">10</span>; i++) {
999  pool.<span class="hljs-title function_">runTask</span>({ <span class="hljs-attr">a</span>: <span class="hljs-number">42</span>, <span class="hljs-attr">b</span>: <span class="hljs-number">100</span> }, <span class="hljs-function">(<span class="hljs-params">err, result</span>) =></span> {
1000    <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(i, err, result);
1001    <span class="hljs-keyword">if</span> (++finished === <span class="hljs-number">10</span>)
1002      pool.<span class="hljs-title function_">close</span>();
1003  });
1004}</code><button class="copy-button">copy</button></pre>
1005<h4>Integrating <code>AsyncResource</code> with <code>EventEmitter</code><span><a class="mark" href="#integrating-asyncresource-with-eventemitter" id="integrating-asyncresource-with-eventemitter">#</a></span><a aria-hidden="true" class="legacy" id="async_context_integrating_asyncresource_with_eventemitter"></a></h4>
1006<p>Event listeners triggered by an <a href="events.html#class-eventemitter"><code>EventEmitter</code></a> may be run in a different
1007execution context than the one that was active when <code>eventEmitter.on()</code> was
1008called.</p>
1009<p>The following example shows how to use the <code>AsyncResource</code> class to properly
1010associate an event listener with the correct execution context. The same
1011approach can be applied to a <a href="stream.html#stream"><code>Stream</code></a> or a similar event-driven class.</p>
1012
1013<pre class="with-72-chars"><input class="js-flavor-selector" type="checkbox" checked aria-label="Show modern ES modules syntax"><code class="language-js mjs"><span class="hljs-keyword">import</span> { createServer } <span class="hljs-keyword">from</span> <span class="hljs-string">'node:http'</span>;
1014<span class="hljs-keyword">import</span> { <span class="hljs-title class_">AsyncResource</span>, executionAsyncId } <span class="hljs-keyword">from</span> <span class="hljs-string">'node:async_hooks'</span>;
1015
1016<span class="hljs-keyword">const</span> server = <span class="hljs-title function_">createServer</span>(<span class="hljs-function">(<span class="hljs-params">req, res</span>) =></span> {
1017  req.<span class="hljs-title function_">on</span>(<span class="hljs-string">'close'</span>, <span class="hljs-title class_">AsyncResource</span>.<span class="hljs-title function_">bind</span>(<span class="hljs-function">() =></span> {
1018    <span class="hljs-comment">// Execution context is bound to the current outer scope.</span>
1019  }));
1020  req.<span class="hljs-title function_">on</span>(<span class="hljs-string">'close'</span>, <span class="hljs-function">() =></span> {
1021    <span class="hljs-comment">// Execution context is bound to the scope that caused 'close' to emit.</span>
1022  });
1023  res.<span class="hljs-title function_">end</span>();
1024}).<span class="hljs-title function_">listen</span>(<span class="hljs-number">3000</span>);</code><code class="language-js cjs"><span class="hljs-keyword">const</span> { createServer } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'node:http'</span>);
1025<span class="hljs-keyword">const</span> { <span class="hljs-title class_">AsyncResource</span>, executionAsyncId } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'node:async_hooks'</span>);
1026
1027<span class="hljs-keyword">const</span> server = <span class="hljs-title function_">createServer</span>(<span class="hljs-function">(<span class="hljs-params">req, res</span>) =></span> {
1028  req.<span class="hljs-title function_">on</span>(<span class="hljs-string">'close'</span>, <span class="hljs-title class_">AsyncResource</span>.<span class="hljs-title function_">bind</span>(<span class="hljs-function">() =></span> {
1029    <span class="hljs-comment">// Execution context is bound to the current outer scope.</span>
1030  }));
1031  req.<span class="hljs-title function_">on</span>(<span class="hljs-string">'close'</span>, <span class="hljs-function">() =></span> {
1032    <span class="hljs-comment">// Execution context is bound to the scope that caused 'close' to emit.</span>
1033  });
1034  res.<span class="hljs-title function_">end</span>();
1035}).<span class="hljs-title function_">listen</span>(<span class="hljs-number">3000</span>);</code><button class="copy-button">copy</button></pre></section>
1036        <!-- API END -->
1037      </div>
1038    </div>
1039  </div>
1040</body>
1041</html>
1042