{"id":22763562,"url":"https://github.com/mearns/extrinsic-promises","last_synced_at":"2025-07-29T22:08:12.259Z","repository":{"id":26873902,"uuid":"111348919","full_name":"mearns/extrinsic-promises","owner":"mearns","description":"A convenient promises anti-pattern: promises you can settle from outside the promise.","archived":false,"fork":false,"pushed_at":"2023-01-07T02:31:22.000Z","size":804,"stargazers_count":1,"open_issues_count":10,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-04-24T19:03:09.198Z","etag":null,"topics":["callbacks","hacktoberfest","javascript","js","promise","promises","reactive","reactive-programming"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mearns.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.yaml","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-11-20T01:47:45.000Z","updated_at":"2021-04-01T19:30:54.000Z","dependencies_parsed_at":"2023-01-14T05:27:51.005Z","dependency_job_id":null,"html_url":"https://github.com/mearns/extrinsic-promises","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/mearns/extrinsic-promises","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mearns%2Fextrinsic-promises","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mearns%2Fextrinsic-promises/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mearns%2Fextrinsic-promises/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mearns%2Fextrinsic-promises/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mearns","download_url":"https://codeload.github.com/mearns/extrinsic-promises/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mearns%2Fextrinsic-promises/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262352530,"owners_count":23297680,"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":["callbacks","hacktoberfest","javascript","js","promise","promises","reactive","reactive-programming"],"created_at":"2024-12-11T11:09:05.355Z","updated_at":"2025-06-28T00:03:24.934Z","avatar_url":"https://github.com/mearns.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Static Badge](https://img.shields.io/badge/deprecated-use_built--in-red)\n[![JavaScript Standard Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)\n\n# extrinsic-promises\n\n_Supports node versions from v6 up to v22, and 0 runtime dependencies_\n\n**Deprecated:** The functionality provided by this module is now available through the built-in\n`Promise` object using the\n[`withResolvers` function (MDN documentation link)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers).\nAs such, this module is being deprecated and will no longer be maintained. See below for migration patterns.\n\n`extrinsic-promises` is a JavaScript module that provides a convenient promises anti-pattern\nfor those times when you just really need to settle (fulfill or reject) your promise from\n_outside_ the promise's work-function.\n\nSpecifically, an `ExtrinsicPromise` is a thennable that you construct _without_ a\nwork-function, and instead call public `fulfill` and `reject` methods on the object\nto settle the state of the promise.\n\n**Note:** this is generally a promises _antipattern_. It is not recommended for most use cases,\nbut there are some situations that can't reasonably be handled with traditional promises (at\nleast not without re-implementing extrinsic-promises.)\n\n## Migrating from this package to built-in functionality\n\nAs of 2023, the JavaScript standard defines a static function called `withResolvers` on the\nbuilt-in `Promise` object. This function provides the same functionality as `extrinsic-promises`,\nand should be preferred going forward. The function has widespread browser support and is available\nby default in NodeJS as of v22. It is also available behind a feature flag as early as Node v21.7.1.\n\nWhile the interface is not a drop-in replacement, all the functionality is easily supported.\n\n### Migration: Creating and settling an externally-settlable promise\n\nOld way:\n\n```javascript\nimport ExtrinsicPromise from \"extrinsic-promises\";\n\nconst promise = new ExtrinsicPromise();\npromise.fulfill(\"some value\");\npromise.reject(new Error(\"some reason\"));\n```\n\nNew way:\n\n```javascript\nconst { promise, resolve, reject } = Promise.withResolvers();\nresolve(\"some value\");\nreject(new Error(\"some reason\"));\n```\n\n### Migration: adopting a thennable\n\nOld way:\n\n```javascript\nimport ExtrinsicPromise from \"extrinsic-promises\";\n\nconst promise = new ExtrinsicPromise();\n\n// ...thennable is a Promise-like object with a then/2 method...\npromise.adopt(thennable);\n```\n\nNew way:\n\n```javascript\nconst { promise, resolve, reject } = Promise.withResolvers();\n\n// ...thennable is a Promise-like object with a then/2 method...\nthennable.then(resolve, reject);\n```\n\n### Migration: replacing the `work` method\n\nOld way:\n\n```javascript\nimport ExtrinsicPromise from \"extrinsic-promises\";\n\nconst promise = new ExtrinsicPromise();\n\nconst myWorkFunction = (fulfill, reject) =\u003e {\n    // ... do some work and then calls either `fulfill` or `reject`.\n};\npromise.work(myWork);\n```\n\nNew way:\n\n```javascript\nconst { promise, resolve, reject } = Promise.withResolvers();\n\nconst myWorkFunction = (fulfill, reject) =\u003e {\n    // ... do some work and then calls either `fulfill` or `reject`.\n};\nsetImmediate(() =\u003e {\n    try {\n        myWorkFunction(resolve, reject);\n    } catch (error) {\n        reject(error);\n    }\n});\n```\n\nOr, new way:\n\n```javascript\nconst myWorkFunction = (fulfill, reject) =\u003e {\n    // ... do some work and then calls either `fulfill` or `reject`.\n};\n\nconst promise = new Promise(myWorkFunction);\n```\n\n### Migration: Hiding the Extrinsic methods\n\nOld way:\n\n```javascript\nimport ExtrinsicPromise from \"extrinsic-promises\";\n\nconst exPromise = new ExtrinsicPromise();\nconst p = exPromise.hide();\np.fulfill; // undefined\np.reject; // undefined\np.adopt; // undefined\np.work; // undefined\np.hide; // undefined\n```\n\nWhen creaeting a promise using `withResolvers`, there's no need to\nhide anything, since the `\"promise\"` property is already just a plain\nPromise.\n\nNew way:\n\n````javascript\nconst { promise: p } = Promise.withResolvers();\np.fulfill; // undefined\np.reject; // undefined\np.adopt; // undefined\np.work; // undefined\np.hide; // undefined\n```\n\n## Installation\n\n```console\nnpm install --save extrinsic-promises\n````\n\n## Example\n\nBasic usage:\n\n```javascript\nimport ExtrinsicPromise from \"extrinsic-promises\";\n\nconst promise = new ExtrinsicPromise();\n\n// Setup handlers for the promise, just like you normally would.\npromise.then(value =\u003e {\n    console.log(\"Promise was fulfilled with value:\", value);\n});\n\n// Call the public methods on the promise to fulfill/resolve it.\npromise.fulfill(\"Some value\");\n```\n\nRejecting a promise:\n\n```javascript\nconst promise = new ExtrinsicPromise();\n\n// Register your on-reject handler for the promise,\n// just like you normally would.\npromise.then(null, reason =\u003e {\n    console.log(\"Promise was reject for reason:\", reason);\n});\n\n// Call the public methods on the promise to reject it.\npromise.reject(new Error(\"some reason\"));\n```\n\n## Getting an Extended API\n\nThe `ExtrinsicPromise` only provides the basic `.then(onFulfill, onReject)` method for promises. If\nyou want the convenience methods provided by your favoritate promises library, you can usually use that\nlibrary to wrap an `ExtrinsicPromise` appropriately:\n\n```javascript\nimport Promise from \"bluebird\";\nimport ExtrinsicPromise from \"extrinsic-promises\";\n\nconst exPromise = new ExtrinsicPromise();\nconst bluebirdPromise = Promise.fulfill(exPromise);\n```\n\nOr, if the library doesn't provide a method like that, you can use the standard `Promise` constructor\nas follows:\n\n```javascript\nimport ExtrinsicPromise from \"extrinsic-promises\";\n\nconst exPromise = new ExtrinsicPromise();\nconst otherPromise = new Promise((fulfill, reject) =\u003e {\n    exPromise.then(fulfill, reject);\n});\n```\n\n## API\n\nThe `ExtrinsicPromise` class exports the following public methods:\n\n### `ExtrinsicPromise::then(onFulfill[, onReject])`\n\nThe standard `then` method of the [Promises/A+](https://promisesaplus.com/#the-then-method) standard,\nused to register an on-fulfill and/or on-reject handler for the promise.\n\n### `ExtrinsicPromise::fulfill([withValue])`\n\nResolve (fulfill) the `ExtrinsicPromise` with the optional given value. Note that there is no gaurantee as to when\nfulfillment occurs (i.e., synchronously or asynchronously).\n\nThis method is already bound and can be used correctly as a function reference. E.g.,:\n\n```javascript\nconst exPromise = new ExtrinsicPromise();\nconst fulfillLater = exPromise.fulfill;\n// ...\nfulfillLater(value); // correctly fulfills exPromise.\n```\n\n### `ExtrinsicPromise::reject([forReason])`\n\nReject the `ExtrinsicPromise` with the optional given reason (typically, an Error object). Note that there is\nno gaurantee as to when rejection occurs (i.e., synchronously or asynchronously).\n\nThis method is already bound and can be used correctly as a function reference. E.g.,:\n\n```javascript\nconst exPromise = new ExtrinsicPromise();\nconst rejectLater = exPromise.reject;\n// ...\nrejectLater(reason); // correctly rejects exPromise.\n```\n\n### `ExtrinsicPromise::adopt(thennable)`\n\nAdopt the state of the given thennable, once the thennable settles, if this extrinsic promise has not _already_\nsettled. This is a convenience for using this extrinsic promise's `fulfill` and `reject` methods as the on-fulfill\nand on-reject handlers, respectively, of the given thennable, as follows:\n\n```javascript\nconst exPromise = new ExtrinsicPromise();\nthennable.then(exPromise.fulfill, exPromise.reject);\n```\n\n### `ExtrinsicPromise::work(workfunction)`\n\nAn alternative interface for settling the promise, this allows you to pass in a work-function just like\nyou normally would pass to the `Promise` constructor, but in this case you're passing it in after the promise\nhas already been constructed.\n\nThe given work function will be invoked _unconditionally_ (even if the promise is already settled) with\ntwo arguments, typically called `fulfill` and `reject`. These are functions that are used to settle the state\nof the promise once the work you promise to do is done, just like the `.fulfill()` and `.reject()` methods on\nthe `ExtrinsicPromise`.\n\nIf an error is thrown inside the workfunction, it will be treated as a rejection.\n\nNote that the work function will be called _asynchronously_, i.e., the call to `.work()` will return _before_\nthe given work function has been called.\n\n### `ExtrinsicPromise::hide()`\n\nReturns a minimal _thennable_ object which only exposes the `.then()` method of this object as a bound function.\nThis allows you to pass around this object as a promise, without exposing it's state-mutating methods like\n`.fulfill()` and `.reject()`.\n\n## How Does it Work?\n\nIt's pretty simple, feel free to read the code. There's a few details necessary to avoid race conditions, but\nthe gist of it is to simply save the `fulfill` and `reject` signalling functions that the promise passes in\nto the work function:\n\n```javascript\nconstructor () {\n  new Promise((fulfill, reject) =\u003e {\n    this.fulfill = fulfill\n    this.reject = reject\n  })\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmearns%2Fextrinsic-promises","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmearns%2Fextrinsic-promises","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmearns%2Fextrinsic-promises/lists"}