From d82d62aed6065ae2e5e3a921df5b92cc1d14ba6c Mon Sep 17 00:00:00 2001 From: Sven Slootweg Date: Wed, 19 Jun 2024 01:27:17 +0200 Subject: [PATCH] Initial version --- README.md | 39 +++++++++++++++++++++++++++++++++++++++ example.js | 17 +++++++++++++++++ index.js | 8 ++++++++ package.json | 20 ++++++++++++++++++++ 4 files changed, 84 insertions(+) create mode 100644 README.md create mode 100644 example.js create mode 100644 index.js create mode 100644 package.json diff --git a/README.md b/README.md new file mode 100644 index 0000000..7d54ed8 --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# capture-promise + +The problem: you want to call a user-supplied callback and expect it to return a Promise, but you don't know if it might throw or return synchronously, and you want to *make sure* that you are dealing with a Promise. + +This solves that problem by capturing all outcomes of a given callback - whether they are synchronous or asynchronous - and always giving you a Promise that resolves or rejects accordingly, much like you would expect an `async` function or `.then` to do. + +Roughly analogous to `Promise.try`. + +## Example + +A runnable version of this example is included in the package as `example.js`. + +```js +"use strict"; + +const capturePromise = require("capture-promise"); + +function dubiousUserSuppliedCallback() { + if (Math.random() < 0.5) { + return Promise.resolve(true); + } else { + throw new Error(`Oops, this is synchronously thrown!`); + } +} + +(async function () { + let promise = capturePromise(() => dubiousUserSuppliedCallback()); + console.log(promise); // Always prints a Promise, regardless of whether the callback throws or not + await promise; // ... and we can await it like any Promise! +})(); +``` + +## API + +### capturePromise(wrapper) + +- __wrapper:__ A callback which calls the dubious function. Note that you __cannot__ directly pass the dubious function (eg. user-supplied callback)! You *must* wrap it in your own callback, like in the example code. + +__Returns:__ A Promise that resolves if the callback returned a resolved Promise or synchronous value; or rejects if the callback returned a rejected Promise or threw a synchronous error. diff --git a/example.js b/example.js new file mode 100644 index 0000000..cde808c --- /dev/null +++ b/example.js @@ -0,0 +1,17 @@ +"use strict"; + +const capturePromise = require("./"); + +function dubiousUserSuppliedCallback() { + if (Math.random() < 0.5) { + return Promise.resolve(true); + } else { + throw new Error(`Oops, this is synchronously thrown!`); + } +} + +(async function () { + let promise = capturePromise(() => dubiousUserSuppliedCallback()); + console.log(promise); // Always prints a Promise, regardless of whether the callback throws or not + await promise; // ... and we can await it like any Promise! +})(); diff --git a/index.js b/index.js new file mode 100644 index 0000000..f7e8e6d --- /dev/null +++ b/index.js @@ -0,0 +1,8 @@ +"use strict"; + +module.exports = function capturePromise(callback) { + // Ensure that any synchronous errors or return values are also handled + return new Promise((resolve, _reject) => { + resolve(callback()); + }); +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..e98059b --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "name": "capture-promise", + "version": "1.0.0", + "description": "Small utility function for safe evaluation of async functions, capturing synchronous outcomes as well", + "main": "index.js", + "repository": { + "url": "https://git.cryto.net/joepie91/capture-promise.git" + }, + "files": [ + "index.js", + "example.js", + "README.md" + ], + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": ["promises", "try", "capture", "error handling", "async"], + "author": "Sven Slootweg ", + "license": "WTFPL OR CC0-1.0" +}