11cb0ef41Sopenharmony_ci# Domain 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ci<!-- YAML 41cb0ef41Sopenharmony_cideprecated: v1.4.2 51cb0ef41Sopenharmony_cichanges: 61cb0ef41Sopenharmony_ci - version: v8.8.0 71cb0ef41Sopenharmony_ci pr-url: https://github.com/nodejs/node/pull/15695 81cb0ef41Sopenharmony_ci description: Any `Promise`s created in VM contexts no longer have a 91cb0ef41Sopenharmony_ci `.domain` property. Their handlers are still executed in the 101cb0ef41Sopenharmony_ci proper domain, however, and `Promise`s created in the main 111cb0ef41Sopenharmony_ci context still possess a `.domain` property. 121cb0ef41Sopenharmony_ci - version: v8.0.0 131cb0ef41Sopenharmony_ci pr-url: https://github.com/nodejs/node/pull/12489 141cb0ef41Sopenharmony_ci description: Handlers for `Promise`s are now invoked in the domain in which 151cb0ef41Sopenharmony_ci the first promise of a chain was created. 161cb0ef41Sopenharmony_ci--> 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_ci<!--introduced_in=v0.10.0--> 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_ci> Stability: 0 - Deprecated 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci<!-- source_link=lib/domain.js --> 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ci**This module is pending deprecation.** Once a replacement API has been 251cb0ef41Sopenharmony_cifinalized, this module will be fully deprecated. Most developers should 261cb0ef41Sopenharmony_ci**not** have cause to use this module. Users who absolutely must have 271cb0ef41Sopenharmony_cithe functionality that domains provide may rely on it for the time being 281cb0ef41Sopenharmony_cibut should expect to have to migrate to a different solution 291cb0ef41Sopenharmony_ciin the future. 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_ciDomains provide a way to handle multiple different IO operations as a 321cb0ef41Sopenharmony_cisingle group. If any of the event emitters or callbacks registered to a 331cb0ef41Sopenharmony_cidomain emit an `'error'` event, or throw an error, then the domain object 341cb0ef41Sopenharmony_ciwill be notified, rather than losing the context of the error in the 351cb0ef41Sopenharmony_ci`process.on('uncaughtException')` handler, or causing the program to 361cb0ef41Sopenharmony_ciexit immediately with an error code. 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_ci## Warning: Don't ignore errors! 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ci<!-- type=misc --> 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ciDomain error handlers are not a substitute for closing down a 431cb0ef41Sopenharmony_ciprocess when an error occurs. 441cb0ef41Sopenharmony_ci 451cb0ef41Sopenharmony_ciBy the very nature of how [`throw`][] works in JavaScript, there is almost 461cb0ef41Sopenharmony_cinever any way to safely "pick up where it left off", without leaking 471cb0ef41Sopenharmony_cireferences, or creating some other sort of undefined brittle state. 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ciThe safest way to respond to a thrown error is to shut down the 501cb0ef41Sopenharmony_ciprocess. Of course, in a normal web server, there may be many 511cb0ef41Sopenharmony_ciopen connections, and it is not reasonable to abruptly shut those down 521cb0ef41Sopenharmony_cibecause an error was triggered by someone else. 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_ciThe better approach is to send an error response to the request that 551cb0ef41Sopenharmony_citriggered the error, while letting the others finish in their normal 561cb0ef41Sopenharmony_citime, and stop listening for new requests in that worker. 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ciIn this way, `domain` usage goes hand-in-hand with the cluster module, 591cb0ef41Sopenharmony_cisince the primary process can fork a new worker when a worker 601cb0ef41Sopenharmony_ciencounters an error. For Node.js programs that scale to multiple 611cb0ef41Sopenharmony_cimachines, the terminating proxy or service registry can take note of 621cb0ef41Sopenharmony_cithe failure, and react accordingly. 631cb0ef41Sopenharmony_ci 641cb0ef41Sopenharmony_ciFor example, this is not a good idea: 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_ci```js 671cb0ef41Sopenharmony_ci// XXX WARNING! BAD IDEA! 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ciconst d = require('node:domain').create(); 701cb0ef41Sopenharmony_cid.on('error', (er) => { 711cb0ef41Sopenharmony_ci // The error won't crash the process, but what it does is worse! 721cb0ef41Sopenharmony_ci // Though we've prevented abrupt process restarting, we are leaking 731cb0ef41Sopenharmony_ci // a lot of resources if this ever happens. 741cb0ef41Sopenharmony_ci // This is no better than process.on('uncaughtException')! 751cb0ef41Sopenharmony_ci console.log(`error, but oh well ${er.message}`); 761cb0ef41Sopenharmony_ci}); 771cb0ef41Sopenharmony_cid.run(() => { 781cb0ef41Sopenharmony_ci require('node:http').createServer((req, res) => { 791cb0ef41Sopenharmony_ci handleRequest(req, res); 801cb0ef41Sopenharmony_ci }).listen(PORT); 811cb0ef41Sopenharmony_ci}); 821cb0ef41Sopenharmony_ci``` 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ciBy using the context of a domain, and the resilience of separating our 851cb0ef41Sopenharmony_ciprogram into multiple worker processes, we can react more 861cb0ef41Sopenharmony_ciappropriately, and handle errors with much greater safety. 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_ci```js 891cb0ef41Sopenharmony_ci// Much better! 901cb0ef41Sopenharmony_ci 911cb0ef41Sopenharmony_ciconst cluster = require('node:cluster'); 921cb0ef41Sopenharmony_ciconst PORT = +process.env.PORT || 1337; 931cb0ef41Sopenharmony_ci 941cb0ef41Sopenharmony_ciif (cluster.isPrimary) { 951cb0ef41Sopenharmony_ci // A more realistic scenario would have more than 2 workers, 961cb0ef41Sopenharmony_ci // and perhaps not put the primary and worker in the same file. 971cb0ef41Sopenharmony_ci // 981cb0ef41Sopenharmony_ci // It is also possible to get a bit fancier about logging, and 991cb0ef41Sopenharmony_ci // implement whatever custom logic is needed to prevent DoS 1001cb0ef41Sopenharmony_ci // attacks and other bad behavior. 1011cb0ef41Sopenharmony_ci // 1021cb0ef41Sopenharmony_ci // See the options in the cluster documentation. 1031cb0ef41Sopenharmony_ci // 1041cb0ef41Sopenharmony_ci // The important thing is that the primary does very little, 1051cb0ef41Sopenharmony_ci // increasing our resilience to unexpected errors. 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ci cluster.fork(); 1081cb0ef41Sopenharmony_ci cluster.fork(); 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_ci cluster.on('disconnect', (worker) => { 1111cb0ef41Sopenharmony_ci console.error('disconnect!'); 1121cb0ef41Sopenharmony_ci cluster.fork(); 1131cb0ef41Sopenharmony_ci }); 1141cb0ef41Sopenharmony_ci 1151cb0ef41Sopenharmony_ci} else { 1161cb0ef41Sopenharmony_ci // the worker 1171cb0ef41Sopenharmony_ci // 1181cb0ef41Sopenharmony_ci // This is where we put our bugs! 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ci const domain = require('node:domain'); 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci // See the cluster documentation for more details about using 1231cb0ef41Sopenharmony_ci // worker processes to serve requests. How it works, caveats, etc. 1241cb0ef41Sopenharmony_ci 1251cb0ef41Sopenharmony_ci const server = require('node:http').createServer((req, res) => { 1261cb0ef41Sopenharmony_ci const d = domain.create(); 1271cb0ef41Sopenharmony_ci d.on('error', (er) => { 1281cb0ef41Sopenharmony_ci console.error(`error ${er.stack}`); 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_ci // We're in dangerous territory! 1311cb0ef41Sopenharmony_ci // By definition, something unexpected occurred, 1321cb0ef41Sopenharmony_ci // which we probably didn't want. 1331cb0ef41Sopenharmony_ci // Anything can happen now! Be very careful! 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_ci try { 1361cb0ef41Sopenharmony_ci // Make sure we close down within 30 seconds 1371cb0ef41Sopenharmony_ci const killtimer = setTimeout(() => { 1381cb0ef41Sopenharmony_ci process.exit(1); 1391cb0ef41Sopenharmony_ci }, 30000); 1401cb0ef41Sopenharmony_ci // But don't keep the process open just for that! 1411cb0ef41Sopenharmony_ci killtimer.unref(); 1421cb0ef41Sopenharmony_ci 1431cb0ef41Sopenharmony_ci // Stop taking new requests. 1441cb0ef41Sopenharmony_ci server.close(); 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_ci // Let the primary know we're dead. This will trigger a 1471cb0ef41Sopenharmony_ci // 'disconnect' in the cluster primary, and then it will fork 1481cb0ef41Sopenharmony_ci // a new worker. 1491cb0ef41Sopenharmony_ci cluster.worker.disconnect(); 1501cb0ef41Sopenharmony_ci 1511cb0ef41Sopenharmony_ci // Try to send an error to the request that triggered the problem 1521cb0ef41Sopenharmony_ci res.statusCode = 500; 1531cb0ef41Sopenharmony_ci res.setHeader('content-type', 'text/plain'); 1541cb0ef41Sopenharmony_ci res.end('Oops, there was a problem!\n'); 1551cb0ef41Sopenharmony_ci } catch (er2) { 1561cb0ef41Sopenharmony_ci // Oh well, not much we can do at this point. 1571cb0ef41Sopenharmony_ci console.error(`Error sending 500! ${er2.stack}`); 1581cb0ef41Sopenharmony_ci } 1591cb0ef41Sopenharmony_ci }); 1601cb0ef41Sopenharmony_ci 1611cb0ef41Sopenharmony_ci // Because req and res were created before this domain existed, 1621cb0ef41Sopenharmony_ci // we need to explicitly add them. 1631cb0ef41Sopenharmony_ci // See the explanation of implicit vs explicit binding below. 1641cb0ef41Sopenharmony_ci d.add(req); 1651cb0ef41Sopenharmony_ci d.add(res); 1661cb0ef41Sopenharmony_ci 1671cb0ef41Sopenharmony_ci // Now run the handler function in the domain. 1681cb0ef41Sopenharmony_ci d.run(() => { 1691cb0ef41Sopenharmony_ci handleRequest(req, res); 1701cb0ef41Sopenharmony_ci }); 1711cb0ef41Sopenharmony_ci }); 1721cb0ef41Sopenharmony_ci server.listen(PORT); 1731cb0ef41Sopenharmony_ci} 1741cb0ef41Sopenharmony_ci 1751cb0ef41Sopenharmony_ci// This part is not important. Just an example routing thing. 1761cb0ef41Sopenharmony_ci// Put fancy application logic here. 1771cb0ef41Sopenharmony_cifunction handleRequest(req, res) { 1781cb0ef41Sopenharmony_ci switch (req.url) { 1791cb0ef41Sopenharmony_ci case '/error': 1801cb0ef41Sopenharmony_ci // We do some async stuff, and then... 1811cb0ef41Sopenharmony_ci setTimeout(() => { 1821cb0ef41Sopenharmony_ci // Whoops! 1831cb0ef41Sopenharmony_ci flerb.bark(); 1841cb0ef41Sopenharmony_ci }, timeout); 1851cb0ef41Sopenharmony_ci break; 1861cb0ef41Sopenharmony_ci default: 1871cb0ef41Sopenharmony_ci res.end('ok'); 1881cb0ef41Sopenharmony_ci } 1891cb0ef41Sopenharmony_ci} 1901cb0ef41Sopenharmony_ci``` 1911cb0ef41Sopenharmony_ci 1921cb0ef41Sopenharmony_ci## Additions to `Error` objects 1931cb0ef41Sopenharmony_ci 1941cb0ef41Sopenharmony_ci<!-- type=misc --> 1951cb0ef41Sopenharmony_ci 1961cb0ef41Sopenharmony_ciAny time an `Error` object is routed through a domain, a few extra fields 1971cb0ef41Sopenharmony_ciare added to it. 1981cb0ef41Sopenharmony_ci 1991cb0ef41Sopenharmony_ci* `error.domain` The domain that first handled the error. 2001cb0ef41Sopenharmony_ci* `error.domainEmitter` The event emitter that emitted an `'error'` event 2011cb0ef41Sopenharmony_ci with the error object. 2021cb0ef41Sopenharmony_ci* `error.domainBound` The callback function which was bound to the 2031cb0ef41Sopenharmony_ci domain, and passed an error as its first argument. 2041cb0ef41Sopenharmony_ci* `error.domainThrown` A boolean indicating whether the error was 2051cb0ef41Sopenharmony_ci thrown, emitted, or passed to a bound callback function. 2061cb0ef41Sopenharmony_ci 2071cb0ef41Sopenharmony_ci## Implicit binding 2081cb0ef41Sopenharmony_ci 2091cb0ef41Sopenharmony_ci<!--type=misc--> 2101cb0ef41Sopenharmony_ci 2111cb0ef41Sopenharmony_ciIf domains are in use, then all **new** `EventEmitter` objects (including 2121cb0ef41Sopenharmony_ciStream objects, requests, responses, etc.) will be implicitly bound to 2131cb0ef41Sopenharmony_cithe active domain at the time of their creation. 2141cb0ef41Sopenharmony_ci 2151cb0ef41Sopenharmony_ciAdditionally, callbacks passed to low-level event loop requests (such as 2161cb0ef41Sopenharmony_cito `fs.open()`, or other callback-taking methods) will automatically be 2171cb0ef41Sopenharmony_cibound to the active domain. If they throw, then the domain will catch 2181cb0ef41Sopenharmony_cithe error. 2191cb0ef41Sopenharmony_ci 2201cb0ef41Sopenharmony_ciIn order to prevent excessive memory usage, `Domain` objects themselves 2211cb0ef41Sopenharmony_ciare not implicitly added as children of the active domain. If they 2221cb0ef41Sopenharmony_ciwere, then it would be too easy to prevent request and response objects 2231cb0ef41Sopenharmony_cifrom being properly garbage collected. 2241cb0ef41Sopenharmony_ci 2251cb0ef41Sopenharmony_ciTo nest `Domain` objects as children of a parent `Domain` they must be 2261cb0ef41Sopenharmony_ciexplicitly added. 2271cb0ef41Sopenharmony_ci 2281cb0ef41Sopenharmony_ciImplicit binding routes thrown errors and `'error'` events to the 2291cb0ef41Sopenharmony_ci`Domain`'s `'error'` event, but does not register the `EventEmitter` on the 2301cb0ef41Sopenharmony_ci`Domain`. 2311cb0ef41Sopenharmony_ciImplicit binding only takes care of thrown errors and `'error'` events. 2321cb0ef41Sopenharmony_ci 2331cb0ef41Sopenharmony_ci## Explicit binding 2341cb0ef41Sopenharmony_ci 2351cb0ef41Sopenharmony_ci<!--type=misc--> 2361cb0ef41Sopenharmony_ci 2371cb0ef41Sopenharmony_ciSometimes, the domain in use is not the one that ought to be used for a 2381cb0ef41Sopenharmony_cispecific event emitter. Or, the event emitter could have been created 2391cb0ef41Sopenharmony_ciin the context of one domain, but ought to instead be bound to some 2401cb0ef41Sopenharmony_ciother domain. 2411cb0ef41Sopenharmony_ci 2421cb0ef41Sopenharmony_ciFor example, there could be one domain in use for an HTTP server, but 2431cb0ef41Sopenharmony_ciperhaps we would like to have a separate domain to use for each request. 2441cb0ef41Sopenharmony_ci 2451cb0ef41Sopenharmony_ciThat is possible via explicit binding. 2461cb0ef41Sopenharmony_ci 2471cb0ef41Sopenharmony_ci```js 2481cb0ef41Sopenharmony_ci// Create a top-level domain for the server 2491cb0ef41Sopenharmony_ciconst domain = require('node:domain'); 2501cb0ef41Sopenharmony_ciconst http = require('node:http'); 2511cb0ef41Sopenharmony_ciconst serverDomain = domain.create(); 2521cb0ef41Sopenharmony_ci 2531cb0ef41Sopenharmony_ciserverDomain.run(() => { 2541cb0ef41Sopenharmony_ci // Server is created in the scope of serverDomain 2551cb0ef41Sopenharmony_ci http.createServer((req, res) => { 2561cb0ef41Sopenharmony_ci // Req and res are also created in the scope of serverDomain 2571cb0ef41Sopenharmony_ci // however, we'd prefer to have a separate domain for each request. 2581cb0ef41Sopenharmony_ci // create it first thing, and add req and res to it. 2591cb0ef41Sopenharmony_ci const reqd = domain.create(); 2601cb0ef41Sopenharmony_ci reqd.add(req); 2611cb0ef41Sopenharmony_ci reqd.add(res); 2621cb0ef41Sopenharmony_ci reqd.on('error', (er) => { 2631cb0ef41Sopenharmony_ci console.error('Error', er, req.url); 2641cb0ef41Sopenharmony_ci try { 2651cb0ef41Sopenharmony_ci res.writeHead(500); 2661cb0ef41Sopenharmony_ci res.end('Error occurred, sorry.'); 2671cb0ef41Sopenharmony_ci } catch (er2) { 2681cb0ef41Sopenharmony_ci console.error('Error sending 500', er2, req.url); 2691cb0ef41Sopenharmony_ci } 2701cb0ef41Sopenharmony_ci }); 2711cb0ef41Sopenharmony_ci }).listen(1337); 2721cb0ef41Sopenharmony_ci}); 2731cb0ef41Sopenharmony_ci``` 2741cb0ef41Sopenharmony_ci 2751cb0ef41Sopenharmony_ci## `domain.create()` 2761cb0ef41Sopenharmony_ci 2771cb0ef41Sopenharmony_ci* Returns: {Domain} 2781cb0ef41Sopenharmony_ci 2791cb0ef41Sopenharmony_ci## Class: `Domain` 2801cb0ef41Sopenharmony_ci 2811cb0ef41Sopenharmony_ci* Extends: {EventEmitter} 2821cb0ef41Sopenharmony_ci 2831cb0ef41Sopenharmony_ciThe `Domain` class encapsulates the functionality of routing errors and 2841cb0ef41Sopenharmony_ciuncaught exceptions to the active `Domain` object. 2851cb0ef41Sopenharmony_ci 2861cb0ef41Sopenharmony_ciTo handle the errors that it catches, listen to its `'error'` event. 2871cb0ef41Sopenharmony_ci 2881cb0ef41Sopenharmony_ci### `domain.members` 2891cb0ef41Sopenharmony_ci 2901cb0ef41Sopenharmony_ci* {Array} 2911cb0ef41Sopenharmony_ci 2921cb0ef41Sopenharmony_ciAn array of timers and event emitters that have been explicitly added 2931cb0ef41Sopenharmony_cito the domain. 2941cb0ef41Sopenharmony_ci 2951cb0ef41Sopenharmony_ci### `domain.add(emitter)` 2961cb0ef41Sopenharmony_ci 2971cb0ef41Sopenharmony_ci* `emitter` {EventEmitter|Timer} emitter or timer to be added to the domain 2981cb0ef41Sopenharmony_ci 2991cb0ef41Sopenharmony_ciExplicitly adds an emitter to the domain. If any event handlers called by 3001cb0ef41Sopenharmony_cithe emitter throw an error, or if the emitter emits an `'error'` event, it 3011cb0ef41Sopenharmony_ciwill be routed to the domain's `'error'` event, just like with implicit 3021cb0ef41Sopenharmony_cibinding. 3031cb0ef41Sopenharmony_ci 3041cb0ef41Sopenharmony_ciThis also works with timers that are returned from [`setInterval()`][] and 3051cb0ef41Sopenharmony_ci[`setTimeout()`][]. If their callback function throws, it will be caught by 3061cb0ef41Sopenharmony_cithe domain `'error'` handler. 3071cb0ef41Sopenharmony_ci 3081cb0ef41Sopenharmony_ciIf the Timer or `EventEmitter` was already bound to a domain, it is removed 3091cb0ef41Sopenharmony_cifrom that one, and bound to this one instead. 3101cb0ef41Sopenharmony_ci 3111cb0ef41Sopenharmony_ci### `domain.bind(callback)` 3121cb0ef41Sopenharmony_ci 3131cb0ef41Sopenharmony_ci* `callback` {Function} The callback function 3141cb0ef41Sopenharmony_ci* Returns: {Function} The bound function 3151cb0ef41Sopenharmony_ci 3161cb0ef41Sopenharmony_ciThe returned function will be a wrapper around the supplied callback 3171cb0ef41Sopenharmony_cifunction. When the returned function is called, any errors that are 3181cb0ef41Sopenharmony_cithrown will be routed to the domain's `'error'` event. 3191cb0ef41Sopenharmony_ci 3201cb0ef41Sopenharmony_ci```js 3211cb0ef41Sopenharmony_ciconst d = domain.create(); 3221cb0ef41Sopenharmony_ci 3231cb0ef41Sopenharmony_cifunction readSomeFile(filename, cb) { 3241cb0ef41Sopenharmony_ci fs.readFile(filename, 'utf8', d.bind((er, data) => { 3251cb0ef41Sopenharmony_ci // If this throws, it will also be passed to the domain. 3261cb0ef41Sopenharmony_ci return cb(er, data ? JSON.parse(data) : null); 3271cb0ef41Sopenharmony_ci })); 3281cb0ef41Sopenharmony_ci} 3291cb0ef41Sopenharmony_ci 3301cb0ef41Sopenharmony_cid.on('error', (er) => { 3311cb0ef41Sopenharmony_ci // An error occurred somewhere. If we throw it now, it will crash the program 3321cb0ef41Sopenharmony_ci // with the normal line number and stack message. 3331cb0ef41Sopenharmony_ci}); 3341cb0ef41Sopenharmony_ci``` 3351cb0ef41Sopenharmony_ci 3361cb0ef41Sopenharmony_ci### `domain.enter()` 3371cb0ef41Sopenharmony_ci 3381cb0ef41Sopenharmony_ciThe `enter()` method is plumbing used by the `run()`, `bind()`, and 3391cb0ef41Sopenharmony_ci`intercept()` methods to set the active domain. It sets `domain.active` and 3401cb0ef41Sopenharmony_ci`process.domain` to the domain, and implicitly pushes the domain onto the domain 3411cb0ef41Sopenharmony_cistack managed by the domain module (see [`domain.exit()`][] for details on the 3421cb0ef41Sopenharmony_cidomain stack). The call to `enter()` delimits the beginning of a chain of 3431cb0ef41Sopenharmony_ciasynchronous calls and I/O operations bound to a domain. 3441cb0ef41Sopenharmony_ci 3451cb0ef41Sopenharmony_ciCalling `enter()` changes only the active domain, and does not alter the domain 3461cb0ef41Sopenharmony_ciitself. `enter()` and `exit()` can be called an arbitrary number of times on a 3471cb0ef41Sopenharmony_cisingle domain. 3481cb0ef41Sopenharmony_ci 3491cb0ef41Sopenharmony_ci### `domain.exit()` 3501cb0ef41Sopenharmony_ci 3511cb0ef41Sopenharmony_ciThe `exit()` method exits the current domain, popping it off the domain stack. 3521cb0ef41Sopenharmony_ciAny time execution is going to switch to the context of a different chain of 3531cb0ef41Sopenharmony_ciasynchronous calls, it's important to ensure that the current domain is exited. 3541cb0ef41Sopenharmony_ciThe call to `exit()` delimits either the end of or an interruption to the chain 3551cb0ef41Sopenharmony_ciof asynchronous calls and I/O operations bound to a domain. 3561cb0ef41Sopenharmony_ci 3571cb0ef41Sopenharmony_ciIf there are multiple, nested domains bound to the current execution context, 3581cb0ef41Sopenharmony_ci`exit()` will exit any domains nested within this domain. 3591cb0ef41Sopenharmony_ci 3601cb0ef41Sopenharmony_ciCalling `exit()` changes only the active domain, and does not alter the domain 3611cb0ef41Sopenharmony_ciitself. `enter()` and `exit()` can be called an arbitrary number of times on a 3621cb0ef41Sopenharmony_cisingle domain. 3631cb0ef41Sopenharmony_ci 3641cb0ef41Sopenharmony_ci### `domain.intercept(callback)` 3651cb0ef41Sopenharmony_ci 3661cb0ef41Sopenharmony_ci* `callback` {Function} The callback function 3671cb0ef41Sopenharmony_ci* Returns: {Function} The intercepted function 3681cb0ef41Sopenharmony_ci 3691cb0ef41Sopenharmony_ciThis method is almost identical to [`domain.bind(callback)`][]. However, in 3701cb0ef41Sopenharmony_ciaddition to catching thrown errors, it will also intercept [`Error`][] 3711cb0ef41Sopenharmony_ciobjects sent as the first argument to the function. 3721cb0ef41Sopenharmony_ci 3731cb0ef41Sopenharmony_ciIn this way, the common `if (err) return callback(err);` pattern can be replaced 3741cb0ef41Sopenharmony_ciwith a single error handler in a single place. 3751cb0ef41Sopenharmony_ci 3761cb0ef41Sopenharmony_ci```js 3771cb0ef41Sopenharmony_ciconst d = domain.create(); 3781cb0ef41Sopenharmony_ci 3791cb0ef41Sopenharmony_cifunction readSomeFile(filename, cb) { 3801cb0ef41Sopenharmony_ci fs.readFile(filename, 'utf8', d.intercept((data) => { 3811cb0ef41Sopenharmony_ci // Note, the first argument is never passed to the 3821cb0ef41Sopenharmony_ci // callback since it is assumed to be the 'Error' argument 3831cb0ef41Sopenharmony_ci // and thus intercepted by the domain. 3841cb0ef41Sopenharmony_ci 3851cb0ef41Sopenharmony_ci // If this throws, it will also be passed to the domain 3861cb0ef41Sopenharmony_ci // so the error-handling logic can be moved to the 'error' 3871cb0ef41Sopenharmony_ci // event on the domain instead of being repeated throughout 3881cb0ef41Sopenharmony_ci // the program. 3891cb0ef41Sopenharmony_ci return cb(null, JSON.parse(data)); 3901cb0ef41Sopenharmony_ci })); 3911cb0ef41Sopenharmony_ci} 3921cb0ef41Sopenharmony_ci 3931cb0ef41Sopenharmony_cid.on('error', (er) => { 3941cb0ef41Sopenharmony_ci // An error occurred somewhere. If we throw it now, it will crash the program 3951cb0ef41Sopenharmony_ci // with the normal line number and stack message. 3961cb0ef41Sopenharmony_ci}); 3971cb0ef41Sopenharmony_ci``` 3981cb0ef41Sopenharmony_ci 3991cb0ef41Sopenharmony_ci### `domain.remove(emitter)` 4001cb0ef41Sopenharmony_ci 4011cb0ef41Sopenharmony_ci* `emitter` {EventEmitter|Timer} emitter or timer to be removed from the domain 4021cb0ef41Sopenharmony_ci 4031cb0ef41Sopenharmony_ciThe opposite of [`domain.add(emitter)`][]. Removes domain handling from the 4041cb0ef41Sopenharmony_cispecified emitter. 4051cb0ef41Sopenharmony_ci 4061cb0ef41Sopenharmony_ci### `domain.run(fn[, ...args])` 4071cb0ef41Sopenharmony_ci 4081cb0ef41Sopenharmony_ci* `fn` {Function} 4091cb0ef41Sopenharmony_ci* `...args` {any} 4101cb0ef41Sopenharmony_ci 4111cb0ef41Sopenharmony_ciRun the supplied function in the context of the domain, implicitly 4121cb0ef41Sopenharmony_cibinding all event emitters, timers, and low-level requests that are 4131cb0ef41Sopenharmony_cicreated in that context. Optionally, arguments can be passed to 4141cb0ef41Sopenharmony_cithe function. 4151cb0ef41Sopenharmony_ci 4161cb0ef41Sopenharmony_ciThis is the most basic way to use a domain. 4171cb0ef41Sopenharmony_ci 4181cb0ef41Sopenharmony_ci```js 4191cb0ef41Sopenharmony_ciconst domain = require('node:domain'); 4201cb0ef41Sopenharmony_ciconst fs = require('node:fs'); 4211cb0ef41Sopenharmony_ciconst d = domain.create(); 4221cb0ef41Sopenharmony_cid.on('error', (er) => { 4231cb0ef41Sopenharmony_ci console.error('Caught error!', er); 4241cb0ef41Sopenharmony_ci}); 4251cb0ef41Sopenharmony_cid.run(() => { 4261cb0ef41Sopenharmony_ci process.nextTick(() => { 4271cb0ef41Sopenharmony_ci setTimeout(() => { // Simulating some various async stuff 4281cb0ef41Sopenharmony_ci fs.open('non-existent file', 'r', (er, fd) => { 4291cb0ef41Sopenharmony_ci if (er) throw er; 4301cb0ef41Sopenharmony_ci // proceed... 4311cb0ef41Sopenharmony_ci }); 4321cb0ef41Sopenharmony_ci }, 100); 4331cb0ef41Sopenharmony_ci }); 4341cb0ef41Sopenharmony_ci}); 4351cb0ef41Sopenharmony_ci``` 4361cb0ef41Sopenharmony_ci 4371cb0ef41Sopenharmony_ciIn this example, the `d.on('error')` handler will be triggered, rather 4381cb0ef41Sopenharmony_cithan crashing the program. 4391cb0ef41Sopenharmony_ci 4401cb0ef41Sopenharmony_ci## Domains and promises 4411cb0ef41Sopenharmony_ci 4421cb0ef41Sopenharmony_ciAs of Node.js 8.0.0, the handlers of promises are run inside the domain in 4431cb0ef41Sopenharmony_ciwhich the call to `.then()` or `.catch()` itself was made: 4441cb0ef41Sopenharmony_ci 4451cb0ef41Sopenharmony_ci```js 4461cb0ef41Sopenharmony_ciconst d1 = domain.create(); 4471cb0ef41Sopenharmony_ciconst d2 = domain.create(); 4481cb0ef41Sopenharmony_ci 4491cb0ef41Sopenharmony_cilet p; 4501cb0ef41Sopenharmony_cid1.run(() => { 4511cb0ef41Sopenharmony_ci p = Promise.resolve(42); 4521cb0ef41Sopenharmony_ci}); 4531cb0ef41Sopenharmony_ci 4541cb0ef41Sopenharmony_cid2.run(() => { 4551cb0ef41Sopenharmony_ci p.then((v) => { 4561cb0ef41Sopenharmony_ci // running in d2 4571cb0ef41Sopenharmony_ci }); 4581cb0ef41Sopenharmony_ci}); 4591cb0ef41Sopenharmony_ci``` 4601cb0ef41Sopenharmony_ci 4611cb0ef41Sopenharmony_ciA callback may be bound to a specific domain using [`domain.bind(callback)`][]: 4621cb0ef41Sopenharmony_ci 4631cb0ef41Sopenharmony_ci```js 4641cb0ef41Sopenharmony_ciconst d1 = domain.create(); 4651cb0ef41Sopenharmony_ciconst d2 = domain.create(); 4661cb0ef41Sopenharmony_ci 4671cb0ef41Sopenharmony_cilet p; 4681cb0ef41Sopenharmony_cid1.run(() => { 4691cb0ef41Sopenharmony_ci p = Promise.resolve(42); 4701cb0ef41Sopenharmony_ci}); 4711cb0ef41Sopenharmony_ci 4721cb0ef41Sopenharmony_cid2.run(() => { 4731cb0ef41Sopenharmony_ci p.then(p.domain.bind((v) => { 4741cb0ef41Sopenharmony_ci // running in d1 4751cb0ef41Sopenharmony_ci })); 4761cb0ef41Sopenharmony_ci}); 4771cb0ef41Sopenharmony_ci``` 4781cb0ef41Sopenharmony_ci 4791cb0ef41Sopenharmony_ciDomains will not interfere with the error handling mechanisms for 4801cb0ef41Sopenharmony_cipromises. In other words, no `'error'` event will be emitted for unhandled 4811cb0ef41Sopenharmony_ci`Promise` rejections. 4821cb0ef41Sopenharmony_ci 4831cb0ef41Sopenharmony_ci[`Error`]: errors.md#class-error 4841cb0ef41Sopenharmony_ci[`domain.add(emitter)`]: #domainaddemitter 4851cb0ef41Sopenharmony_ci[`domain.bind(callback)`]: #domainbindcallback 4861cb0ef41Sopenharmony_ci[`domain.exit()`]: #domainexit 4871cb0ef41Sopenharmony_ci[`setInterval()`]: timers.md#setintervalcallback-delay-args 4881cb0ef41Sopenharmony_ci[`setTimeout()`]: timers.md#settimeoutcallback-delay-args 4891cb0ef41Sopenharmony_ci[`throw`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw 490