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