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">►</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-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">►</span><span class="expanded-arrow">▼</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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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"><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 < 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 < 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 < <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 < <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