Some things that are "better" with this BetterPromise
implementation:
-
BetterPromise # then(..)
accepts aBetterPromise
(orPromise
) instance passed directly, instead of requiring a function to return it, so that the promise is linked into the chain.var p = BetterPromise.resolve(42); var q = Promise.resolve(10); p.then(console.log).then(q).then(console.log); // 42 // 10
-
BetterPromise # unthen(..)
/BetterPromise # uncatch(..)
/BetterPromise # unfinally(..)
allows you to unregister a fulfillment or rejection handler that you previously registered on a promise viathen(..)
orcatch(..)
, or unregister a resolution handler that you previously registered on a promise viafinally(..)
.NOTE: This seems to be the majority use-case for why many like/want "promise cancelation" -- IOW, often what you want is to just stop observing a promise's resolution, not actually forcibly cancel the operation is comes from.
var p = new BetterPromise(function(res){ setTimeout(function(){ res(42); },100); }); function f1(v) { console.log(`f1: ${v}`); } function f2(v) { console.log(`f2: ${v}`); } function f3() { console.log("finally!"); } p.then(f1); p.then(f2); p.finally(f3); p.unthen(f1); p.unfinally(f3); // later // f2: 42
-
BetterPromise # finally(..)
is included (assumed implemented since it's already stage-4). Registers a resolution handler which is called on either fulfillment or rejection, sorta like if you didthen( fn, fn )
(but not exactly).var p = BetterPromise.resolve(42); p .finally(function(){ console.log("resolved!"); }) .then(function(v){ console.log(`still: ${v}`); }); // resolved! // still: 42
-
BetterPromise # thenLog()
/BetterPromise # catchLog()
inserts a step in a promise chain that simply prints the value to the console (console.log
for fulfillment,console.error
for rejection) and passes the value or rejection along to the next step untouched.var p = BetterPromise.resolve(42); p .thenLog() .then(function(v){ console.log(`still: ${v}`); }); // 42 // still: 42
-
Instead of silently being swallowed, if a synchronous exception is thrown in a
BetterPromise
constructor after the promise has already been synchronously resolved (fulfillment or rejection), that exception overrides and causes the promise to be rejected with that exception.var p = new BetterPromise(function(res){ res(42); throw 10; }); p.then( function(v){ console.log(`then: ${v}`); }, function(e){ console.log(`oops: ${e}`); } ); // oops: 10
-
BetterPromise.try(..)
(static helper) is implemented (so not just draft). Runs a function (with no arguments) synchronously, returns a promise for its return value (or adopts its promise), catches any synchronous exception and turns it into a rejection.var p = BetterPromise.try(function(){ undefined(42); }); p.catch(console.log); // TypeError: undefined is not a function
-
BetterPromise.deferred(..)
(static helper) constructs an instance of the promise, but also extracts itsresolve(..)
andreject(..)
capabilities, and returns all 3 in an object (aka, a "deferred").var { pr, resolve, reject } = BetterPromise.deferred(); pr.then(console.log); resolve(42); // 42
-
BetterPromise.lift(..)
(static helper) lifts an error-first, callback-last style function to beBetterPromise
returning instead.var readFile = BetterPromise.lift(fs.readFile); readFile("/path/to/file.txt") .then(printContents);
-
BetterPromise.control(..)
(static helper) wraps a function so that when called, it first creates anAbortController
instance, passes in itssignal
as the first argument to the original function, and returns a controller object that has both apr
for the function's completion, as well as acancel(..)
to send the abort signal. Ostensibly, the original function can then observe/respond to that passed-in signal and do something appropriate with it, like canceling its own behavior, passing it tofetch(..)
to abort an Ajax call, etc.async function main(signal,url) { signal.addEventListener("abort", .. ); // .. var resp = await fetch(url, { signal }); // .. } var fn = BetterPromise.control(main); var { pr, cancel } = fn("http://some.url"); pr.then(..); // later cancel(); // sends cancelation signal into `fn(..)`
@getify
quick aside: I read YDKJS & am currently working through Functional-Light JavaScript. Thank you so much for those awesome tomes of knowledge.
Now onwards.
I been heavily researching how one can make native promises more effective.
Here is something sitting inside my head for awhile, and I think I almost see this in your deferred method here. The real question is: Is there a way to make a Promise something like a Future? e.g. like in Python or Rust (for reference, because its cleaner than the Python doc IMO, https://docs.rs/futures/0.2.1/futures )
For instance, say you want to call an AJAX request at the beginning of a page load, but want the results to be held in a Future until you're ready to access them. The benefit here is that you would call the say, Promise.Future early in the code, fire off the async AJAX request, but somewhere else you call future.result() and retrieve those bits.
Aslo, to address var vs let.
Why not use const for variables in a limited scope and let for everything else? Conveys the same meaning semantically without confusion. Just curious. Also less text editors will freak out about it :)