{"id":19874509,"url":"https://github.com/strongloop/zone","last_synced_at":"2025-04-04T08:08:23.216Z","repository":{"id":13826372,"uuid":"16523016","full_name":"strongloop/zone","owner":"strongloop","description":"Flow control and error handling for Node.js","archived":false,"fork":false,"pushed_at":"2024-04-26T04:32:13.000Z","size":612,"stargazers_count":280,"open_issues_count":20,"forks_count":14,"subscribers_count":32,"default_branch":"master","last_synced_at":"2024-04-26T05:15:11.730Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://strongloop.com/zone","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/strongloop.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-02-04T19:33:26.000Z","updated_at":"2024-06-18T15:19:06.207Z","dependencies_parsed_at":"2024-06-18T15:19:00.512Z","dependency_job_id":null,"html_url":"https://github.com/strongloop/zone","commit_stats":{"total_commits":366,"total_committers":9,"mean_commits":"40.666666666666664","dds":0.2295081967213115,"last_synced_commit":"15f4f0f8a1438617d53d3985fe0db5a572abb1d2"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strongloop%2Fzone","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strongloop%2Fzone/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strongloop%2Fzone/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/strongloop%2Fzone/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/strongloop","download_url":"https://codeload.github.com/strongloop/zone/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247142066,"owners_count":20890652,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-12T16:23:44.492Z","updated_at":"2025-04-04T08:08:23.199Z","avatar_url":"https://github.com/strongloop.png","language":"JavaScript","funding_links":[],"categories":["Packages","包"],"sub_categories":["Control flow Other","Control flow"],"readme":"**NOTE: This project is deprecated and no longer being actively developed or maintained.**  See [Issue #50](https://github.com/strongloop/zone/issues/50) for details.\n\n# StrongLoop zone library\n\n## Overview\n\nThe Zone library provides a way to represent the dynamic extent of asynchronous calls in Node. Just like the scope of a function defines where it may be used, the extent of a call represents the lifetime that is it active.\n\nA Zone also provides execution context that can persist across the lifecycle of one or more asynchronous calls. This is similar to the concept of thread-local data in Java.\n\nZones provide a way to group and track resources and errors across asynchronous operations. In addition zones:\n\n  * Enables more effective debugging by providing better stack traces for asynchronous functions\n  * Makes it easier to write and understand asynchronous functions for Node applications\n  * Makes it easier to handle errors raised asynchronously and avoid resulting resource leaks\n  * Enables you to associate user data with asynchronous control flow\n  \n[Dart's async library](https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/dart-async.Zone) and [Brian Ford's zone.js](https://github.com/btford/zone.js/) library provide similar functionality.\n\n## Implementation status\n\n* The zone library dynamically modifies Node's asynchronous APIs at runtime.\n  As detailed below, some of the modules have not yet been completed, and thus you cannot use them with zones.\n  \n  The following modules have not been zone enabled:\n  \n  - cluster\n  - crypto: `pbkdf2`, `randomBytes`, `pseudoRandomBytes`\n  - fs: `fs.watch`, `fs.watchFile`, `fs.FSWatcher`\n  - process object: `process.on('SIGHUP')` and other signals.\n  - tls / https\n  - udp\n  - zlib\n\n## Using zones\n\nTo use zones, add the following as the very first line of your program:\n\n```js\nrequire('zone').enable();\n```\n\nThe zone library exports a global variable, `zone`. The `zone` global variable always refers to the currently active zone. Some methods that can always be found on the 'zone' object are actually static methods of the `Zone` class, so they don't do anything with the currently active zone.\n\nAfter loading the zone library the program has entered the 'root' zone.\n\n### Creating a zone\n\nThere are a few different ways to create a zone. The canonical way to create a one-off zone is:\n\n```js\n// Load the library\nrequire('zone').enable();\n\n// MyZone is the name of this zone which shows up in stack traces.\nzone.create(function MyZone() {\n  // At this point the 'zone' global points at the zone instance (\"MyZone\")\n  // that we just created.\n});\n```\n\nThe zone constructor function is called synchronously.\n\n#### Defining zone functions\n\nUnder some circumstances it may be desirable to create a function that is always wrapped within a zone.\nThe obvious way to do this:\n\n```js\nfunction renderTemplate(fileName, cb) {\n  zone.create(function() {\n    // Actual work here\n    ...\n  }).setCallback(cb);\n}\n```\n\nTo make this a little less verbose there is the 'zone.define()' API.\nWith it you can wrap a function such that when it's called a zone is created.\nExample:\n\n```js\nvar renderTemplate = zone.define(function(fileName, cb) {\n  zone.setCallback(cb);\n  // Actual work here\n  ...\n});\n```\n\nNow you can use this zone template as follows:\n\n```js\nrenderTemplate('bar', function(err, result) {\n  if (err)\n    throw err;\n  // Do something with the result\n  ...\n});\n```\n\n### Obtaining the result of a zone\n\nZones are like asynchronous functions. From the outside perspective, they can return a single value or \"throw\" a single error. There are a couple of ways the outside zone may obtain the result of a zone. When a zone reports its outcome:\n\n  * No more callbacks will run inside the zone.\n  * All non-garbage-collectable resources have been cleaned up.\n\nZones also automatically exit when no explicit value is returned.\n\nA way to obtain the outcome of a zone is:\n\n```js\nrequire('zone').enable();\nvar net = require('net');\n\nzone.create(function MyZone() {\n  // This runs in the context of MyZone\n  net.createConnection(...);\n  fs.stat(...)\n\n  if (Math.random() \u003c 0.5)\n    throw new Error('Chaos monkey!');\n  else if (Math.random() \u003c 0.5)\n    zone.return('Chaos monkey in disguise!');\n  else\n    ; // Wait for the zone to auto-exit.\n\n}).setCallback(function(err, result) {\n  // Here we're back in the root zone.\n  // Asynchronicity is guaranteed, even if the zone returns or throws immediately.\n  // By the time we get here we are sure:\n  //   * the connection has been closed one way or another\n  //   * fs.stat has completed\n});\n```\n\nYou can also use the `then` and `catch` methods, as if it were a promise.\nNote that unlike promises you can't currently chain calls callbacks.\n\n```js\nzone.create(function MyZone() {\n  // Do whatever\n}).then(function(result) {\n  // Runs when succesful\n}).catch(function(err) {\n  // Handle error\n});\n```\n\n### Sharing resources between zones\n\nWithin a zone you may use resources that are \"owned\" by ancestor zones. So this is okay:\n\n```js\nvar server = http.createServer().listen(1234);\nserver.listen(1234);\n\nzone.create(function ServerZone() {\n  // Yes, allowed.\n  server.on('connection', function(req, res) { ... });\n\n  // Totally okay\n  process.stdout.write('hello!');\n});\n```\n\nHowever, using resources owned by child zones is not allowed:\n\n```js\nvar server;\n\nzone.create(function SomeZone() {\n server = http.createServer().listen(1234);\n});\n\n// NOT OKAY!\nserver.on('connection', function() { ... });\n```\n\nNOTE: Currently zones don't always enforce these rules, but you're not supposed to do this. It would also be dumb, since the server will disappear when `SomeZone()` exits itself!\n\n### The rules of engagement\n\nIt is okay for a zone to temporarily enter an ancestor zone. It is not\nallowed to enter child zones, siblings, etc. The rationale behind this is\nthat when a zone is alive its parent must also be alive. Other zones\nmay exit unless they are aware that code will run inside them.\n\n```js\nzone.create(function OuterZone() {\n  var childZone = zone.create(function ChildZone() {\n    ...\n  });\n\n  // Fine.\n  zone.parent.run(function() {\n    console.log('Hello from the root zone!');\n  });\n\n  // NOT ALLOWED\n  childZone.run(function() {\n    console.log('Weird. This isn't supposed to work!');\n  });\n});\n```\n\n### Exiting a zone\n\nThere are a few ways to explicitly exit a zone:\n\n* `zone.return(value)` sets the return value of the zone and starts cleanup.\n* `zone.throw(error)` sets the zone to failed state and starts cleanup. `zone.throw` itself does not throw, so statements after it will run.\n* `throw error` uses normal exception handling. If the exception is not caught before it reaches the binding layer, the active zone is set to failed state and starts cleanup.\n* `zone.complete(err, value)` is a zone-bound function that may be passed to subordinates to let them exit the zone.\n\nA rather pointless example:\n\n```js\nzone.create(function StatZone() {\n  fs.stat('/some/file', function(err, result) {\n    if (err)\n      throw err;\n    else\n      zone.return(result);\n  });\n});\n```\n\nThis is equivalent to:\n\n```js\nzone.create(function StatZone() {\n  fs.stat('/some/file', zone.complete);\n});\n```\n\nTo run code in a child zone, you can use `zone.bindCallback` and `zone.bindAsyncCallback` to create a callback object which can be invoked from a parent zone.\n\n### Sharing resources between zones\n\nWithin a zone you may use resources that are \"owned\" by ancestor zones. So this is okay:\n\n```js\nvar server = http.createServer().listen(1234);\nserver.listen(1234);\n\nzone.create(function ServerZone() {\n  // Yes, allowed.\n  server.on('connection', function(req, res) { ... });\n\n  // Totally okay\n  process.stdout.write('hello!');\n});\n```\n\nHowever, using resources owned by child zones is not allowed:\n\n```js\nvar server;\n\nzone.create(function SomeZone() {\n server = http.createServer().listen(1234);\n});\n\n// NOT OKAY!\nserver.on('connection', function() { ... });\n```\n\nNOTE: Currently zones don't always enforce these rules, but you're not supposed to do this.\nIt would also be dumb, since the server will disappear when `SomeZone()` exits itself!\n\n### Zone.data\n\nzone.data is a magical property that that associates arbitrary data with a zone.\nIn a way you can think of it as the 'scope' of a zone. Properties that are not explicitly defined within the scope of a zone are inherited from the parent zone.\n\n  * In the root zone, `zone.data` equals the global object.\n  * In any other zone, `zone.data` starts off as an empty object with the parent zone's `data` property as it's prototype.\n  * In other words, `zone.data.__proto__ === zone.parent.data`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstrongloop%2Fzone","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstrongloop%2Fzone","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstrongloop%2Fzone/lists"}