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.18.2"> 7 <title>Asynchronous context tracking | Node.js v18.18.2 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.18.2 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.18.2</li> 115 116 <li class="picker-header"> 117 <a href="#"> 118 <span class="collapsed-arrow">►</span><span class="expanded-arrow">▼</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">►</span><span class="expanded-arrow">▼</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">►</span><span class="expanded-arrow">▼</span> 247 Other versions 248 </a> 249 <div class="picker"><ol id="alt-docs"><li><a href="https://nodejs.org/docs/latest-v20.x/api/async_context.html">20.x</a></li> 250<li><a href="https://nodejs.org/docs/latest-v19.x/api/async_context.html">19.x</a></li> 251<li><a href="https://nodejs.org/docs/latest-v18.x/api/async_context.html">18.x <b>LTS</b></a></li> 252<li><a href="https://nodejs.org/docs/latest-v17.x/api/async_context.html">17.x</a></li> 253<li><a href="https://nodejs.org/docs/latest-v16.x/api/async_context.html">16.x</a></li></ol></div> 254 </li> 255 256 <li class="picker-header"> 257 <a href="#"> 258 <span class="collapsed-arrow">►</span><span class="expanded-arrow">▼</span> 259 Options 260 </a> 261 262 <div class="picker"> 263 <ul> 264 <li> 265 <a href="all.html">View on single page</a> 266 </li> 267 <li> 268 <a href="async_context.json">View as JSON</a> 269 </li> 270 <li class="edit_on_github"><a href="https://github.com/nodejs/node/edit/main/doc/api/async_context.md">Edit on GitHub</a></li> 271 </ul> 272 </div> 273 </li> 274 </ul> 275 </div> 276 <hr> 277 </header> 278 279 <details id="toc" open><summary>Table of contents</summary><ul> 280<li><span class="stability_2"><a href="#asynchronous-context-tracking">Asynchronous context tracking</a></span> 281<ul> 282<li><a href="#introduction">Introduction</a></li> 283<li><a href="#class-asynclocalstorage">Class: <code>AsyncLocalStorage</code></a> 284<ul> 285<li><a href="#new-asynclocalstorage"><code>new AsyncLocalStorage()</code></a></li> 286<li><span class="stability_1"><a href="#static-method-asynclocalstoragebindfn">Static method: <code>AsyncLocalStorage.bind(fn)</code></a></span></li> 287<li><span class="stability_1"><a href="#static-method-asynclocalstoragesnapshot">Static method: <code>AsyncLocalStorage.snapshot()</code></a></span></li> 288<li><span class="stability_1"><a href="#asynclocalstoragedisable"><code>asyncLocalStorage.disable()</code></a></span></li> 289<li><a href="#asynclocalstoragegetstore"><code>asyncLocalStorage.getStore()</code></a></li> 290<li><span class="stability_1"><a href="#asynclocalstorageenterwithstore"><code>asyncLocalStorage.enterWith(store)</code></a></span></li> 291<li><a href="#asynclocalstoragerunstore-callback-args"><code>asyncLocalStorage.run(store, callback[, ...args])</code></a></li> 292<li><span class="stability_1"><a href="#asynclocalstorageexitcallback-args"><code>asyncLocalStorage.exit(callback[, ...args])</code></a></span></li> 293<li><a href="#usage-with-asyncawait">Usage with <code>async/await</code></a></li> 294<li><a href="#troubleshooting-context-loss">Troubleshooting: Context loss</a></li> 295</ul> 296</li> 297<li><a href="#class-asyncresource">Class: <code>AsyncResource</code></a> 298<ul> 299<li><a href="#new-asyncresourcetype-options"><code>new AsyncResource(type[, options])</code></a></li> 300<li><a href="#static-method-asyncresourcebindfn-type-thisarg">Static method: <code>AsyncResource.bind(fn[, type[, thisArg]])</code></a></li> 301<li><a href="#asyncresourcebindfn-thisarg"><code>asyncResource.bind(fn[, thisArg])</code></a></li> 302<li><a href="#asyncresourceruninasyncscopefn-thisarg-args"><code>asyncResource.runInAsyncScope(fn[, thisArg, ...args])</code></a></li> 303<li><a href="#asyncresourceemitdestroy"><code>asyncResource.emitDestroy()</code></a></li> 304<li><a href="#asyncresourceasyncid"><code>asyncResource.asyncId()</code></a></li> 305<li><a href="#asyncresourcetriggerasyncid"><code>asyncResource.triggerAsyncId()</code></a></li> 306<li><a href="#using-asyncresource-for-a-worker-thread-pool">Using <code>AsyncResource</code> for a <code>Worker</code> thread pool</a></li> 307<li><a href="#integrating-asyncresource-with-eventemitter">Integrating <code>AsyncResource</code> with <code>EventEmitter</code></a></li> 308</ul> 309</li> 310</ul> 311</li> 312</ul></details> 313 314 <div id="apicontent"> 315 <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> 316 317<p></p><div class="api_stability api_stability_2"><a href="documentation.html#stability-index">Stability: 2</a> - Stable</div><p></p> 318<p><strong>Source Code:</strong> <a href="https://github.com/nodejs/node/blob/v18.18.2/lib/async_hooks.js">lib/async_hooks.js</a></p> 319<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> 320<p>These classes are used to associate state and propagate it throughout 321callbacks and promise chains. 322They allow storing data throughout the lifetime of a web request 323or any other asynchronous duration. It is similar to thread-local storage 324in other languages.</p> 325<p>The <code>AsyncLocalStorage</code> and <code>AsyncResource</code> classes are part of the 326<code>node:async_hooks</code> module:</p> 327 328<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> 329</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> 330<div class="api_metadata"> 331<details class="changelog"><summary>History</summary> 332<table> 333<tbody><tr><th>Version</th><th>Changes</th></tr> 334<tr><td>v16.4.0</td> 335<td><p>AsyncLocalStorage is now Stable. Previously, it had been Experimental.</p></td></tr> 336<tr><td>v13.10.0, v12.17.0</td> 337<td><p><span>Added in: v13.10.0, v12.17.0</span></p></td></tr> 338</tbody></table> 339</details> 340</div> 341<p>This class creates stores that stay coherent through asynchronous operations.</p> 342<p>While you can create your own implementation on top of the <code>node:async_hooks</code> 343module, <code>AsyncLocalStorage</code> should be preferred as it is a performant and memory 344safe implementation that involves significant optimizations that are non-obvious 345to implement.</p> 346<p>The following example uses <code>AsyncLocalStorage</code> to build a simple logger 347that assigns IDs to incoming HTTP requests and includes them in messages 348logged within each request.</p> 349 350<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>; 351<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>; 352 353<span class="hljs-keyword">const</span> asyncLocalStorage = <span class="hljs-keyword">new</span> <span class="hljs-title class_">AsyncLocalStorage</span>(); 354 355<span class="hljs-keyword">function</span> <span class="hljs-title function_">logWithId</span>(<span class="hljs-params">msg</span>) { 356 <span class="hljs-keyword">const</span> id = asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); 357 <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); 358} 359 360<span class="hljs-keyword">let</span> idSeq = <span class="hljs-number">0</span>; 361http.<span class="hljs-title function_">createServer</span>(<span class="hljs-function">(<span class="hljs-params">req, res</span>) =></span> { 362 asyncLocalStorage.<span class="hljs-title function_">run</span>(idSeq++, <span class="hljs-function">() =></span> { 363 <span class="hljs-title function_">logWithId</span>(<span class="hljs-string">'start'</span>); 364 <span class="hljs-comment">// Imagine any chain of async operations here</span> 365 <span class="hljs-title function_">setImmediate</span>(<span class="hljs-function">() =></span> { 366 <span class="hljs-title function_">logWithId</span>(<span class="hljs-string">'finish'</span>); 367 res.<span class="hljs-title function_">end</span>(); 368 }); 369 }); 370}).<span class="hljs-title function_">listen</span>(<span class="hljs-number">8080</span>); 371 372http.<span class="hljs-title function_">get</span>(<span class="hljs-string">'http://localhost:8080'</span>); 373http.<span class="hljs-title function_">get</span>(<span class="hljs-string">'http://localhost:8080'</span>); 374<span class="hljs-comment">// Prints:</span> 375<span class="hljs-comment">// 0: start</span> 376<span class="hljs-comment">// 1: start</span> 377<span class="hljs-comment">// 0: finish</span> 378<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>); 379<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>); 380 381<span class="hljs-keyword">const</span> asyncLocalStorage = <span class="hljs-keyword">new</span> <span class="hljs-title class_">AsyncLocalStorage</span>(); 382 383<span class="hljs-keyword">function</span> <span class="hljs-title function_">logWithId</span>(<span class="hljs-params">msg</span>) { 384 <span class="hljs-keyword">const</span> id = asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); 385 <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); 386} 387 388<span class="hljs-keyword">let</span> idSeq = <span class="hljs-number">0</span>; 389http.<span class="hljs-title function_">createServer</span>(<span class="hljs-function">(<span class="hljs-params">req, res</span>) =></span> { 390 asyncLocalStorage.<span class="hljs-title function_">run</span>(idSeq++, <span class="hljs-function">() =></span> { 391 <span class="hljs-title function_">logWithId</span>(<span class="hljs-string">'start'</span>); 392 <span class="hljs-comment">// Imagine any chain of async operations here</span> 393 <span class="hljs-title function_">setImmediate</span>(<span class="hljs-function">() =></span> { 394 <span class="hljs-title function_">logWithId</span>(<span class="hljs-string">'finish'</span>); 395 res.<span class="hljs-title function_">end</span>(); 396 }); 397 }); 398}).<span class="hljs-title function_">listen</span>(<span class="hljs-number">8080</span>); 399 400http.<span class="hljs-title function_">get</span>(<span class="hljs-string">'http://localhost:8080'</span>); 401http.<span class="hljs-title function_">get</span>(<span class="hljs-string">'http://localhost:8080'</span>); 402<span class="hljs-comment">// Prints:</span> 403<span class="hljs-comment">// 0: start</span> 404<span class="hljs-comment">// 1: start</span> 405<span class="hljs-comment">// 0: finish</span> 406<span class="hljs-comment">// 1: finish</span></code><button class="copy-button">copy</button></pre> 407<p>Each instance of <code>AsyncLocalStorage</code> maintains an independent storage context. 408Multiple instances can safely exist simultaneously without risk of interfering 409with each other's data.</p> 410<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> 411<div class="api_metadata"> 412<details class="changelog"><summary>History</summary> 413<table> 414<tbody><tr><th>Version</th><th>Changes</th></tr> 415<tr><td>v18.16.0</td> 416<td><p>Removed experimental onPropagate option.</p></td></tr> 417<tr><td>v18.13.0</td> 418<td><p>Add option onPropagate.</p></td></tr> 419<tr><td>v13.10.0, v12.17.0</td> 420<td><p><span>Added in: v13.10.0, v12.17.0</span></p></td></tr> 421</tbody></table> 422</details> 423</div> 424<p>Creates a new instance of <code>AsyncLocalStorage</code>. Store is only provided within a 425<code>run()</code> call or after an <code>enterWith()</code> call.</p> 426<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> 427<div class="api_metadata"> 428<span>Added in: v18.16.0</span> 429</div> 430<p></p><div class="api_stability api_stability_1"><a href="documentation.html#stability-index">Stability: 1</a> - Experimental</div><p></p> 431<ul> 432<li><code>fn</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function" class="type"><Function></a> The function to bind to the current execution context.</li> 433<li>Returns: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function" class="type"><Function></a> A new function that calls <code>fn</code> within the captured 434execution context.</li> 435</ul> 436<p>Binds the given function to the current execution context.</p> 437<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> 438<div class="api_metadata"> 439<span>Added in: v18.16.0</span> 440</div> 441<p></p><div class="api_stability api_stability_1"><a href="documentation.html#stability-index">Stability: 1</a> - Experimental</div><p></p> 442<ul> 443<li>Returns: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function" class="type"><Function></a> A new function with the signature 444<code>(fn: (...args) : R, ...args) : R</code>.</li> 445</ul> 446<p>Captures the current execution context and returns a function that accepts a 447function as an argument. Whenever the returned function is called, it 448calls the function passed to it within the captured context.</p> 449<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>(); 450<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>()); 451<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>())); 452<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> 453<p>AsyncLocalStorage.snapshot() can replace the use of AsyncResource for simple 454async context tracking purposes, for example:</p> 455<pre><code class="language-js"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Foo</span> { 456 #runInAsyncScope = <span class="hljs-title class_">AsyncLocalStorage</span>.<span class="hljs-title function_">snapshot</span>(); 457 458 <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>()); } 459} 460 461<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>()); 462<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> 463<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> 464<div class="api_metadata"> 465<span>Added in: v13.10.0, v12.17.0</span> 466</div> 467<p></p><div class="api_stability api_stability_1"><a href="documentation.html#stability-index">Stability: 1</a> - Experimental</div><p></p> 468<p>Disables the instance of <code>AsyncLocalStorage</code>. All subsequent calls 469to <code>asyncLocalStorage.getStore()</code> will return <code>undefined</code> until 470<code>asyncLocalStorage.run()</code> or <code>asyncLocalStorage.enterWith()</code> is called again.</p> 471<p>When calling <code>asyncLocalStorage.disable()</code>, all current contexts linked to the 472instance will be exited.</p> 473<p>Calling <code>asyncLocalStorage.disable()</code> is required before the 474<code>asyncLocalStorage</code> can be garbage collected. This does not apply to stores 475provided by the <code>asyncLocalStorage</code>, as those objects are garbage collected 476along with the corresponding async resources.</p> 477<p>Use this method when the <code>asyncLocalStorage</code> is not in use anymore 478in the current process.</p> 479<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> 480<div class="api_metadata"> 481<span>Added in: v13.10.0, v12.17.0</span> 482</div> 483<ul> 484<li>Returns: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type"><any></a></li> 485</ul> 486<p>Returns the current store. 487If called outside of an asynchronous context initialized by 488calling <code>asyncLocalStorage.run()</code> or <code>asyncLocalStorage.enterWith()</code>, it 489returns <code>undefined</code>.</p> 490<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> 491<div class="api_metadata"> 492<span>Added in: v13.11.0, v12.17.0</span> 493</div> 494<p></p><div class="api_stability api_stability_1"><a href="documentation.html#stability-index">Stability: 1</a> - Experimental</div><p></p> 495<ul> 496<li><code>store</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type"><any></a></li> 497</ul> 498<p>Transitions into the context for the remainder of the current 499synchronous execution and then persists the store through any following 500asynchronous calls.</p> 501<p>Example:</p> 502<pre><code class="language-js"><span class="hljs-keyword">const</span> store = { <span class="hljs-attr">id</span>: <span class="hljs-number">1</span> }; 503<span class="hljs-comment">// Replaces previous store with the given store object</span> 504asyncLocalStorage.<span class="hljs-title function_">enterWith</span>(store); 505asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); <span class="hljs-comment">// Returns the store object</span> 506<span class="hljs-title function_">someAsyncOperation</span>(<span class="hljs-function">() =></span> { 507 asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); <span class="hljs-comment">// Returns the same object</span> 508});</code> <button class="copy-button">copy</button></pre> 509<p>This transition will continue for the <em>entire</em> synchronous execution. 510This means that if, for example, the context is entered within an event 511handler subsequent event handlers will also run within that context unless 512specifically bound to another context with an <code>AsyncResource</code>. That is why 513<code>run()</code> should be preferred over <code>enterWith()</code> unless there are strong reasons 514to use the latter method.</p> 515<pre><code class="language-js"><span class="hljs-keyword">const</span> store = { <span class="hljs-attr">id</span>: <span class="hljs-number">1</span> }; 516 517emitter.<span class="hljs-title function_">on</span>(<span class="hljs-string">'my-event'</span>, <span class="hljs-function">() =></span> { 518 asyncLocalStorage.<span class="hljs-title function_">enterWith</span>(store); 519}); 520emitter.<span class="hljs-title function_">on</span>(<span class="hljs-string">'my-event'</span>, <span class="hljs-function">() =></span> { 521 asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); <span class="hljs-comment">// Returns the same object</span> 522}); 523 524asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); <span class="hljs-comment">// Returns undefined</span> 525emitter.<span class="hljs-title function_">emit</span>(<span class="hljs-string">'my-event'</span>); 526asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); <span class="hljs-comment">// Returns the same object</span></code> <button class="copy-button">copy</button></pre> 527<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> 528<div class="api_metadata"> 529<span>Added in: v13.10.0, v12.17.0</span> 530</div> 531<ul> 532<li><code>store</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type"><any></a></li> 533<li><code>callback</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function" class="type"><Function></a></li> 534<li><code>...args</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type"><any></a></li> 535</ul> 536<p>Runs a function synchronously within a context and returns its 537return value. The store is not accessible outside of the callback function. 538The store is accessible to any asynchronous operations created within the 539callback.</p> 540<p>The optional <code>args</code> are passed to the callback function.</p> 541<p>If the callback function throws an error, the error is thrown by <code>run()</code> too. 542The stacktrace is not impacted by this call and the context is exited.</p> 543<p>Example:</p> 544<pre><code class="language-js"><span class="hljs-keyword">const</span> store = { <span class="hljs-attr">id</span>: <span class="hljs-number">2</span> }; 545<span class="hljs-keyword">try</span> { 546 asyncLocalStorage.<span class="hljs-title function_">run</span>(store, <span class="hljs-function">() =></span> { 547 asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); <span class="hljs-comment">// Returns the store object</span> 548 <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =></span> { 549 asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); <span class="hljs-comment">// Returns the store object</span> 550 }, <span class="hljs-number">200</span>); 551 <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Error</span>(); 552 }); 553} <span class="hljs-keyword">catch</span> (e) { 554 asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); <span class="hljs-comment">// Returns undefined</span> 555 <span class="hljs-comment">// The error will be caught here</span> 556}</code> <button class="copy-button">copy</button></pre> 557<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> 558<div class="api_metadata"> 559<span>Added in: v13.10.0, v12.17.0</span> 560</div> 561<p></p><div class="api_stability api_stability_1"><a href="documentation.html#stability-index">Stability: 1</a> - Experimental</div><p></p> 562<ul> 563<li><code>callback</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function" class="type"><Function></a></li> 564<li><code>...args</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type"><any></a></li> 565</ul> 566<p>Runs a function synchronously outside of a context and returns its 567return value. The store is not accessible within the callback function or 568the asynchronous operations created within the callback. Any <code>getStore()</code> 569call done within the callback function will always return <code>undefined</code>.</p> 570<p>The optional <code>args</code> are passed to the callback function.</p> 571<p>If the callback function throws an error, the error is thrown by <code>exit()</code> too. 572The stacktrace is not impacted by this call and the context is re-entered.</p> 573<p>Example:</p> 574<pre><code class="language-js"><span class="hljs-comment">// Within a call to run</span> 575<span class="hljs-keyword">try</span> { 576 asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); <span class="hljs-comment">// Returns the store object or value</span> 577 asyncLocalStorage.<span class="hljs-title function_">exit</span>(<span class="hljs-function">() =></span> { 578 asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); <span class="hljs-comment">// Returns undefined</span> 579 <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Error</span>(); 580 }); 581} <span class="hljs-keyword">catch</span> (e) { 582 asyncLocalStorage.<span class="hljs-title function_">getStore</span>(); <span class="hljs-comment">// Returns the same object or value</span> 583 <span class="hljs-comment">// The error will be caught here</span> 584}</code> <button class="copy-button">copy</button></pre> 585<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> 586<p>If, within an async function, only one <code>await</code> call is to run within a context, 587the following pattern should be used:</p> 588<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>) { 589 <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> { 590 asyncLocalStorage.<span class="hljs-title function_">getStore</span>().<span class="hljs-title function_">set</span>(<span class="hljs-string">'key'</span>, value); 591 <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> 592 }); 593}</code> <button class="copy-button">copy</button></pre> 594<p>In this example, the store is only available in the callback function and the 595functions called by <code>foo</code>. Outside of <code>run</code>, calling <code>getStore</code> will return 596<code>undefined</code>.</p> 597<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> 598<p>In most cases, <code>AsyncLocalStorage</code> works without issues. In rare situations, the 599current store is lost in one of the asynchronous operations.</p> 600<p>If your code is callback-based, it is enough to promisify it with 601<a href="util.html#utilpromisifyoriginal"><code>util.promisify()</code></a> so it starts working with native promises.</p> 602<p>If you need to use a callback-based API or your code assumes 603a custom thenable implementation, use the <a href="#class-asyncresource"><code>AsyncResource</code></a> class 604to associate the asynchronous operation with the correct execution context. 605Find the function call responsible for the context loss by logging the content 606of <code>asyncLocalStorage.getStore()</code> after the calls you suspect are responsible 607for the loss. When the code logs <code>undefined</code>, the last callback called is 608probably responsible for the context loss.</p> 609</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> 610<div class="api_metadata"> 611<details class="changelog"><summary>History</summary> 612<table> 613<tbody><tr><th>Version</th><th>Changes</th></tr> 614<tr><td>v16.4.0</td> 615<td><p>AsyncResource is now Stable. Previously, it had been Experimental.</p></td></tr> 616</tbody></table> 617</details> 618</div> 619<p>The class <code>AsyncResource</code> is designed to be extended by the embedder's async 620resources. Using this, users can easily trigger the lifetime events of their 621own resources.</p> 622<p>The <code>init</code> hook will trigger when an <code>AsyncResource</code> is instantiated.</p> 623<p>The following is an overview of the <code>AsyncResource</code> API.</p> 624 625<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>; 626 627<span class="hljs-comment">// AsyncResource() is meant to be extended. Instantiating a</span> 628<span class="hljs-comment">// new AsyncResource() also triggers init. If triggerAsyncId is omitted then</span> 629<span class="hljs-comment">// async_hook.executionAsyncId() is used.</span> 630<span class="hljs-keyword">const</span> asyncResource = <span class="hljs-keyword">new</span> <span class="hljs-title class_">AsyncResource</span>( 631 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> }, 632); 633 634<span class="hljs-comment">// Run a function in the execution context of the resource. This will</span> 635<span class="hljs-comment">// * establish the context of the resource</span> 636<span class="hljs-comment">// * trigger the AsyncHooks before callbacks</span> 637<span class="hljs-comment">// * call the provided function `fn` with the supplied arguments</span> 638<span class="hljs-comment">// * trigger the AsyncHooks after callbacks</span> 639<span class="hljs-comment">// * restore the original execution context</span> 640asyncResource.<span class="hljs-title function_">runInAsyncScope</span>(fn, thisArg, ...args); 641 642<span class="hljs-comment">// Call AsyncHooks destroy callbacks.</span> 643asyncResource.<span class="hljs-title function_">emitDestroy</span>(); 644 645<span class="hljs-comment">// Return the unique ID assigned to the AsyncResource instance.</span> 646asyncResource.<span class="hljs-title function_">asyncId</span>(); 647 648<span class="hljs-comment">// Return the trigger ID for the AsyncResource instance.</span> 649asyncResource.<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>); 650 651<span class="hljs-comment">// AsyncResource() is meant to be extended. Instantiating a</span> 652<span class="hljs-comment">// new AsyncResource() also triggers init. If triggerAsyncId is omitted then</span> 653<span class="hljs-comment">// async_hook.executionAsyncId() is used.</span> 654<span class="hljs-keyword">const</span> asyncResource = <span class="hljs-keyword">new</span> <span class="hljs-title class_">AsyncResource</span>( 655 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> }, 656); 657 658<span class="hljs-comment">// Run a function in the execution context of the resource. This will</span> 659<span class="hljs-comment">// * establish the context of the resource</span> 660<span class="hljs-comment">// * trigger the AsyncHooks before callbacks</span> 661<span class="hljs-comment">// * call the provided function `fn` with the supplied arguments</span> 662<span class="hljs-comment">// * trigger the AsyncHooks after callbacks</span> 663<span class="hljs-comment">// * restore the original execution context</span> 664asyncResource.<span class="hljs-title function_">runInAsyncScope</span>(fn, thisArg, ...args); 665 666<span class="hljs-comment">// Call AsyncHooks destroy callbacks.</span> 667asyncResource.<span class="hljs-title function_">emitDestroy</span>(); 668 669<span class="hljs-comment">// Return the unique ID assigned to the AsyncResource instance.</span> 670asyncResource.<span class="hljs-title function_">asyncId</span>(); 671 672<span class="hljs-comment">// Return the trigger ID for the AsyncResource instance.</span> 673asyncResource.<span class="hljs-title function_">triggerAsyncId</span>();</code><button class="copy-button">copy</button></pre> 674<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> 675<ul> 676<li><code>type</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type" class="type"><string></a> The type of async event.</li> 677<li><code>options</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object" class="type"><Object></a> 678<ul> 679<li><code>triggerAsyncId</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type" class="type"><number></a> The ID of the execution context that created this 680async event. <strong>Default:</strong> <code>executionAsyncId()</code>.</li> 681<li><code>requireManualDestroy</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Boolean_type" class="type"><boolean></a> If set to <code>true</code>, disables <code>emitDestroy</code> 682when the object is garbage collected. This usually does not need to be set 683(even if <code>emitDestroy</code> is called manually), unless the resource's <code>asyncId</code> 684is retrieved and the sensitive API's <code>emitDestroy</code> is called with it. 685When set to <code>false</code>, the <code>emitDestroy</code> call on garbage collection 686will only take place if there is at least one active <code>destroy</code> hook. 687<strong>Default:</strong> <code>false</code>.</li> 688</ul> 689</li> 690</ul> 691<p>Example usage:</p> 692<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> { 693 <span class="hljs-title function_">constructor</span>(<span class="hljs-params">db</span>) { 694 <span class="hljs-variable language_">super</span>(<span class="hljs-string">'DBQuery'</span>); 695 <span class="hljs-variable language_">this</span>.<span class="hljs-property">db</span> = db; 696 } 697 698 <span class="hljs-title function_">getInfo</span>(<span class="hljs-params">query, callback</span>) { 699 <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> { 700 <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">runInAsyncScope</span>(callback, <span class="hljs-literal">null</span>, err, data); 701 }); 702 } 703 704 <span class="hljs-title function_">close</span>(<span class="hljs-params"></span>) { 705 <span class="hljs-variable language_">this</span>.<span class="hljs-property">db</span> = <span class="hljs-literal">null</span>; 706 <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">emitDestroy</span>(); 707 } 708}</code> <button class="copy-button">copy</button></pre> 709<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> 710<div class="api_metadata"> 711<details class="changelog"><summary>History</summary> 712<table> 713<tbody><tr><th>Version</th><th>Changes</th></tr> 714<tr><td>v17.8.0</td> 715<td><p>Changed the default when <code>thisArg</code> is undefined to use <code>this</code> from the caller.</p></td></tr> 716<tr><td>v16.0.0</td> 717<td><p>Added optional thisArg.</p></td></tr> 718<tr><td>v14.8.0, v12.19.0</td> 719<td><p><span>Added in: v14.8.0, v12.19.0</span></p></td></tr> 720</tbody></table> 721</details> 722</div> 723<ul> 724<li><code>fn</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function" class="type"><Function></a> The function to bind to the current execution context.</li> 725<li><code>type</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type" class="type"><string></a> An optional name to associate with the underlying 726<code>AsyncResource</code>.</li> 727<li><code>thisArg</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type"><any></a></li> 728</ul> 729<p>Binds the given function to the current execution context.</p> 730<p>The returned function will have an <code>asyncResource</code> property referencing 731the <code>AsyncResource</code> to which the function is bound.</p> 732<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> 733<div class="api_metadata"> 734<details class="changelog"><summary>History</summary> 735<table> 736<tbody><tr><th>Version</th><th>Changes</th></tr> 737<tr><td>v17.8.0</td> 738<td><p>Changed the default when <code>thisArg</code> is undefined to use <code>this</code> from the caller.</p></td></tr> 739<tr><td>v16.0.0</td> 740<td><p>Added optional thisArg.</p></td></tr> 741<tr><td>v14.8.0, v12.19.0</td> 742<td><p><span>Added in: v14.8.0, v12.19.0</span></p></td></tr> 743</tbody></table> 744</details> 745</div> 746<ul> 747<li><code>fn</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function" class="type"><Function></a> The function to bind to the current <code>AsyncResource</code>.</li> 748<li><code>thisArg</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type"><any></a></li> 749</ul> 750<p>Binds the given function to execute to this <code>AsyncResource</code>'s scope.</p> 751<p>The returned function will have an <code>asyncResource</code> property referencing 752the <code>AsyncResource</code> to which the function is bound.</p> 753<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> 754<div class="api_metadata"> 755<span>Added in: v9.6.0</span> 756</div> 757<ul> 758<li><code>fn</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function" class="type"><Function></a> The function to call in the execution context of this async 759resource.</li> 760<li><code>thisArg</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type"><any></a> The receiver to be used for the function call.</li> 761<li><code>...args</code> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Data_types" class="type"><any></a> Optional arguments to pass to the function.</li> 762</ul> 763<p>Call the provided function with the provided arguments in the execution context 764of the async resource. This will establish the context, trigger the AsyncHooks 765before callbacks, call the function, trigger the AsyncHooks after callbacks, and 766then restore the original execution context.</p> 767<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> 768<ul> 769<li>Returns: <a href="async_hooks.html#class-asyncresource" class="type"><AsyncResource></a> A reference to <code>asyncResource</code>.</li> 770</ul> 771<p>Call all <code>destroy</code> hooks. This should only ever be called once. An error will 772be thrown if it is called more than once. This <strong>must</strong> be manually called. If 773the resource is left to be collected by the GC then the <code>destroy</code> hooks will 774never be called.</p> 775<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> 776<ul> 777<li>Returns: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type" class="type"><number></a> The unique <code>asyncId</code> assigned to the resource.</li> 778</ul> 779<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> 780<ul> 781<li>Returns: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type" class="type"><number></a> The same <code>triggerAsyncId</code> that is passed to the 782<code>AsyncResource</code> constructor.</li> 783</ul> 784<p><a id="async-resource-worker-pool"></a></p> 785<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> 786<p>The following example shows how to use the <code>AsyncResource</code> class to properly 787provide async tracking for a <a href="worker_threads.html#class-worker"><code>Worker</code></a> pool. Other resource pools, such as 788database connection pools, can follow a similar model.</p> 789<p>Assuming that the task is adding two numbers, using a file named 790<code>task_processor.js</code> with the following content:</p> 791 792<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>; 793parentPort.<span class="hljs-title function_">on</span>(<span class="hljs-string">'message'</span>, <span class="hljs-function">(<span class="hljs-params">task</span>) =></span> { 794 parentPort.<span class="hljs-title function_">postMessage</span>(task.<span class="hljs-property">a</span> + task.<span class="hljs-property">b</span>); 795});</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>); 796parentPort.<span class="hljs-title function_">on</span>(<span class="hljs-string">'message'</span>, <span class="hljs-function">(<span class="hljs-params">task</span>) =></span> { 797 parentPort.<span class="hljs-title function_">postMessage</span>(task.<span class="hljs-property">a</span> + task.<span class="hljs-property">b</span>); 798});</code><button class="copy-button">copy</button></pre> 799<p>a Worker pool around it could use the following structure:</p> 800 801<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>; 802<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>; 803<span class="hljs-keyword">import</span> path <span class="hljs-keyword">from</span> <span class="hljs-string">'node:path'</span>; 804<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>; 805 806<span class="hljs-keyword">const</span> kTaskInfo = <span class="hljs-title class_">Symbol</span>(<span class="hljs-string">'kTaskInfo'</span>); 807<span class="hljs-keyword">const</span> kWorkerFreedEvent = <span class="hljs-title class_">Symbol</span>(<span class="hljs-string">'kWorkerFreedEvent'</span>); 808 809<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> { 810 <span class="hljs-title function_">constructor</span>(<span class="hljs-params">callback</span>) { 811 <span class="hljs-variable language_">super</span>(<span class="hljs-string">'WorkerPoolTaskInfo'</span>); 812 <span class="hljs-variable language_">this</span>.<span class="hljs-property">callback</span> = callback; 813 } 814 815 <span class="hljs-title function_">done</span>(<span class="hljs-params">err, result</span>) { 816 <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); 817 <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> 818 } 819} 820 821<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> { 822 <span class="hljs-title function_">constructor</span>(<span class="hljs-params">numThreads</span>) { 823 <span class="hljs-variable language_">super</span>(); 824 <span class="hljs-variable language_">this</span>.<span class="hljs-property">numThreads</span> = numThreads; 825 <span class="hljs-variable language_">this</span>.<span class="hljs-property">workers</span> = []; 826 <span class="hljs-variable language_">this</span>.<span class="hljs-property">freeWorkers</span> = []; 827 <span class="hljs-variable language_">this</span>.<span class="hljs-property">tasks</span> = []; 828 829 <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i < numThreads; i++) 830 <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">addNewWorker</span>(); 831 832 <span class="hljs-comment">// Any time the kWorkerFreedEvent is emitted, dispatch</span> 833 <span class="hljs-comment">// the next task pending in the queue, if any.</span> 834 <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">on</span>(kWorkerFreedEvent, <span class="hljs-function">() =></span> { 835 <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>) { 836 <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>(); 837 <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">runTask</span>(task, callback); 838 } 839 }); 840 } 841 842 <span class="hljs-title function_">addNewWorker</span>(<span class="hljs-params"></span>) { 843 <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>)); 844 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> { 845 <span class="hljs-comment">// In case of success: Call the callback that was passed to `runTask`,</span> 846 <span class="hljs-comment">// remove the `TaskInfo` associated with the Worker, and mark it as free</span> 847 <span class="hljs-comment">// again.</span> 848 worker[kTaskInfo].<span class="hljs-title function_">done</span>(<span class="hljs-literal">null</span>, result); 849 worker[kTaskInfo] = <span class="hljs-literal">null</span>; 850 <span class="hljs-variable language_">this</span>.<span class="hljs-property">freeWorkers</span>.<span class="hljs-title function_">push</span>(worker); 851 <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">emit</span>(kWorkerFreedEvent); 852 }); 853 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> { 854 <span class="hljs-comment">// In case of an uncaught exception: Call the callback that was passed to</span> 855 <span class="hljs-comment">// `runTask` with the error.</span> 856 <span class="hljs-keyword">if</span> (worker[kTaskInfo]) 857 worker[kTaskInfo].<span class="hljs-title function_">done</span>(err, <span class="hljs-literal">null</span>); 858 <span class="hljs-keyword">else</span> 859 <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">emit</span>(<span class="hljs-string">'error'</span>, err); 860 <span class="hljs-comment">// Remove the worker from the list and start a new Worker to replace the</span> 861 <span class="hljs-comment">// current one.</span> 862 <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>); 863 <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">addNewWorker</span>(); 864 }); 865 <span class="hljs-variable language_">this</span>.<span class="hljs-property">workers</span>.<span class="hljs-title function_">push</span>(worker); 866 <span class="hljs-variable language_">this</span>.<span class="hljs-property">freeWorkers</span>.<span class="hljs-title function_">push</span>(worker); 867 <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">emit</span>(kWorkerFreedEvent); 868 } 869 870 <span class="hljs-title function_">runTask</span>(<span class="hljs-params">task, callback</span>) { 871 <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>) { 872 <span class="hljs-comment">// No free threads, wait until a worker thread becomes free.</span> 873 <span class="hljs-variable language_">this</span>.<span class="hljs-property">tasks</span>.<span class="hljs-title function_">push</span>({ task, callback }); 874 <span class="hljs-keyword">return</span>; 875 } 876 877 <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>(); 878 worker[kTaskInfo] = <span class="hljs-keyword">new</span> <span class="hljs-title class_">WorkerPoolTaskInfo</span>(callback); 879 worker.<span class="hljs-title function_">postMessage</span>(task); 880 } 881 882 <span class="hljs-title function_">close</span>(<span class="hljs-params"></span>) { 883 <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>(); 884 } 885}</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>); 886<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>); 887<span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">'node:path'</span>); 888<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>); 889 890<span class="hljs-keyword">const</span> kTaskInfo = <span class="hljs-title class_">Symbol</span>(<span class="hljs-string">'kTaskInfo'</span>); 891<span class="hljs-keyword">const</span> kWorkerFreedEvent = <span class="hljs-title class_">Symbol</span>(<span class="hljs-string">'kWorkerFreedEvent'</span>); 892 893<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> { 894 <span class="hljs-title function_">constructor</span>(<span class="hljs-params">callback</span>) { 895 <span class="hljs-variable language_">super</span>(<span class="hljs-string">'WorkerPoolTaskInfo'</span>); 896 <span class="hljs-variable language_">this</span>.<span class="hljs-property">callback</span> = callback; 897 } 898 899 <span class="hljs-title function_">done</span>(<span class="hljs-params">err, result</span>) { 900 <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); 901 <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> 902 } 903} 904 905<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> { 906 <span class="hljs-title function_">constructor</span>(<span class="hljs-params">numThreads</span>) { 907 <span class="hljs-variable language_">super</span>(); 908 <span class="hljs-variable language_">this</span>.<span class="hljs-property">numThreads</span> = numThreads; 909 <span class="hljs-variable language_">this</span>.<span class="hljs-property">workers</span> = []; 910 <span class="hljs-variable language_">this</span>.<span class="hljs-property">freeWorkers</span> = []; 911 <span class="hljs-variable language_">this</span>.<span class="hljs-property">tasks</span> = []; 912 913 <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i < numThreads; i++) 914 <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">addNewWorker</span>(); 915 916 <span class="hljs-comment">// Any time the kWorkerFreedEvent is emitted, dispatch</span> 917 <span class="hljs-comment">// the next task pending in the queue, if any.</span> 918 <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">on</span>(kWorkerFreedEvent, <span class="hljs-function">() =></span> { 919 <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>) { 920 <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>(); 921 <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">runTask</span>(task, callback); 922 } 923 }); 924 } 925 926 <span class="hljs-title function_">addNewWorker</span>(<span class="hljs-params"></span>) { 927 <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>)); 928 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> { 929 <span class="hljs-comment">// In case of success: Call the callback that was passed to `runTask`,</span> 930 <span class="hljs-comment">// remove the `TaskInfo` associated with the Worker, and mark it as free</span> 931 <span class="hljs-comment">// again.</span> 932 worker[kTaskInfo].<span class="hljs-title function_">done</span>(<span class="hljs-literal">null</span>, result); 933 worker[kTaskInfo] = <span class="hljs-literal">null</span>; 934 <span class="hljs-variable language_">this</span>.<span class="hljs-property">freeWorkers</span>.<span class="hljs-title function_">push</span>(worker); 935 <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">emit</span>(kWorkerFreedEvent); 936 }); 937 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> { 938 <span class="hljs-comment">// In case of an uncaught exception: Call the callback that was passed to</span> 939 <span class="hljs-comment">// `runTask` with the error.</span> 940 <span class="hljs-keyword">if</span> (worker[kTaskInfo]) 941 worker[kTaskInfo].<span class="hljs-title function_">done</span>(err, <span class="hljs-literal">null</span>); 942 <span class="hljs-keyword">else</span> 943 <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">emit</span>(<span class="hljs-string">'error'</span>, err); 944 <span class="hljs-comment">// Remove the worker from the list and start a new Worker to replace the</span> 945 <span class="hljs-comment">// current one.</span> 946 <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>); 947 <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">addNewWorker</span>(); 948 }); 949 <span class="hljs-variable language_">this</span>.<span class="hljs-property">workers</span>.<span class="hljs-title function_">push</span>(worker); 950 <span class="hljs-variable language_">this</span>.<span class="hljs-property">freeWorkers</span>.<span class="hljs-title function_">push</span>(worker); 951 <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">emit</span>(kWorkerFreedEvent); 952 } 953 954 <span class="hljs-title function_">runTask</span>(<span class="hljs-params">task, callback</span>) { 955 <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>) { 956 <span class="hljs-comment">// No free threads, wait until a worker thread becomes free.</span> 957 <span class="hljs-variable language_">this</span>.<span class="hljs-property">tasks</span>.<span class="hljs-title function_">push</span>({ task, callback }); 958 <span class="hljs-keyword">return</span>; 959 } 960 961 <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>(); 962 worker[kTaskInfo] = <span class="hljs-keyword">new</span> <span class="hljs-title class_">WorkerPoolTaskInfo</span>(callback); 963 worker.<span class="hljs-title function_">postMessage</span>(task); 964 } 965 966 <span class="hljs-title function_">close</span>(<span class="hljs-params"></span>) { 967 <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>(); 968 } 969} 970 971<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> 972<p>Without the explicit tracking added by the <code>WorkerPoolTaskInfo</code> objects, 973it would appear that the callbacks are associated with the individual <code>Worker</code> 974objects. However, the creation of the <code>Worker</code>s is not associated with the 975creation of the tasks and does not provide information about when tasks 976were scheduled.</p> 977<p>This pool could be used as follows:</p> 978 979<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>; 980<span class="hljs-keyword">import</span> os <span class="hljs-keyword">from</span> <span class="hljs-string">'node:os'</span>; 981 982<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>()); 983 984<span class="hljs-keyword">let</span> finished = <span class="hljs-number">0</span>; 985<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-number">10</span>; i++) { 986 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> { 987 <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(i, err, result); 988 <span class="hljs-keyword">if</span> (++finished === <span class="hljs-number">10</span>) 989 pool.<span class="hljs-title function_">close</span>(); 990 }); 991}</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>); 992<span class="hljs-keyword">const</span> os = <span class="hljs-built_in">require</span>(<span class="hljs-string">'node:os'</span>); 993 994<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>()); 995 996<span class="hljs-keyword">let</span> finished = <span class="hljs-number">0</span>; 997<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i < <span class="hljs-number">10</span>; i++) { 998 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> { 999 <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(i, err, result); 1000 <span class="hljs-keyword">if</span> (++finished === <span class="hljs-number">10</span>) 1001 pool.<span class="hljs-title function_">close</span>(); 1002 }); 1003}</code><button class="copy-button">copy</button></pre> 1004<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> 1005<p>Event listeners triggered by an <a href="events.html#class-eventemitter"><code>EventEmitter</code></a> may be run in a different 1006execution context than the one that was active when <code>eventEmitter.on()</code> was 1007called.</p> 1008<p>The following example shows how to use the <code>AsyncResource</code> class to properly 1009associate an event listener with the correct execution context. The same 1010approach can be applied to a <a href="stream.html#stream"><code>Stream</code></a> or a similar event-driven class.</p> 1011 1012<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>; 1013<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>; 1014 1015<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> { 1016 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> { 1017 <span class="hljs-comment">// Execution context is bound to the current outer scope.</span> 1018 })); 1019 req.<span class="hljs-title function_">on</span>(<span class="hljs-string">'close'</span>, <span class="hljs-function">() =></span> { 1020 <span class="hljs-comment">// Execution context is bound to the scope that caused 'close' to emit.</span> 1021 }); 1022 res.<span class="hljs-title function_">end</span>(); 1023}).<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>); 1024<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>); 1025 1026<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> { 1027 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> { 1028 <span class="hljs-comment">// Execution context is bound to the current outer scope.</span> 1029 })); 1030 req.<span class="hljs-title function_">on</span>(<span class="hljs-string">'close'</span>, <span class="hljs-function">() =></span> { 1031 <span class="hljs-comment">// Execution context is bound to the scope that caused 'close' to emit.</span> 1032 }); 1033 res.<span class="hljs-title function_">end</span>(); 1034}).<span class="hljs-title function_">listen</span>(<span class="hljs-number">3000</span>);</code><button class="copy-button">copy</button></pre></section> 1035 <!-- API END --> 1036 </div> 1037 </div> 1038 </div> 1039</body> 1040</html> 1041