Linting Promises in Javascript - javascript

I am looking to standardize the use of Q promises in my team's codebase. Are there any good jscs extensions (or other linters) to help enforce style when it comes to promises?
We would like our promises to follow this form:
promise()
.then()
.catch()
.done();
And would like a linter to catch any .then() in our code that is missing a .catch()
Advice for other stylistic tips when it comes to promises is welcome too.

#Jeff that approach looks as total overkill. Neither of this functions must be followed with any. Each of them has different purpose:
Use then(mapSuccess, mapFail) when you want to process resolved value and you need a result promise that will resolve with value returned by callback.
Technically it's a mapping of value into other value which will be resolved by other promise. You may think of it similarly as of array's map with which you map input array into other which is result of some transformation function.
catch(mapFail) is purely alias for then(null, mapFail), So just use it when you want to then but you have no need to pass mapSuccess callback.
done(onSuccess, onFail) use simply, when all you want to do is to process resolved value (no need for mapping to other promise). done will also assure that all eventual errors are naturally exposed (then and catch as they're mappers, swallow errors into promise results).
I can imagine only one rule, which can be added for linter (and it's assuming that you use library which doesn't log swallowed exceptions). It's to warn about then() or catch() usages when their results are being ignored (they should be followed by done(..) or passed to other entity for processing).

Related

Custom thenables: Can I create my own objects with a "then" method?

I'm wondering if custom "thenables" (aka an object with a .then() method) are approved/documented? How do they compare to real Promises? I suppose it matters how you implement then, so I'm wondering if there's documentation with some DOs and DONTs.
This page suggests:
.then may return an arbitrary “thenable” object, and it will be treated the same way as a promise.
Can't find any docs on this.
How do thenables compare to real Promises?
In that you don't know whether they are real promises or not. Have a look at Regarding Promises/A+ Specification, what is the difference between the terms "thenable" and "promise"?.
I'm wondering if there's documentation with some DOs and DONTs about how to implement them (as that seems to be what matters)
There's the (pretty simple) Promises/A+ specification that documents how thenables are treated. ES6 promises (and by extension, await) follow this. Basically:
your object has a property with the name then whose value is a function
the function will get called with two callbacks
you can call either of them - asynchronously or not
the first call determines what happens to the promise that assimilated your thenable
It's really no magic. You call the first argument when you want to resolve with a value, and you call the second argument when you want to reject. There are no DONTs assuming a proper promise implementation - you can call the callbacks as often as you want, and keep them around as long as you want: the calls should be ignored and the reference should not leak memory.

promise chain resolves before its last promise resolves

Background
Started with 2 nearly identical javascripts then refactored into 3: a utility script containing formerly redundant code + 2 calling scripts.
Problem
The two original scripts use jquery Deferreds (when.then) and work fine. The 3-script scenario fails because the next-to-last promise resolves early from one calling script.
Details
The first script, call it "multi" uses a sequence of deferreds to loop through a series of ajax requests and then refreshes the "multi" page in the browser. So:
auth -> user -> loop (updateIssue -> transition) end loop -> refresh
The 2nd, "single" uses effectively the same code without the loop, and then a different refresh function
My aim was to refactor the code into a promise chain in a utility script and use like so:
// calling script
Utility.promiseChain().done(refresh())
// utility script
Utility.promiseChain = function() {
return authPromise()
.then(function() { return userPromise();} )
.then(function() { return Promise.all(array of update.then(transition) promises);})}
The Problem, More Specifically
The Promise.all call ALWAYS resolves after update, but before transition, causing the refresh to fire early, followed by the transition. Any insight you can provide will be most helpful.
The Promise.all call ALWAYS resolves after update, but before transition
The only way that can happen is if something in your chain of events is not properly chaining promises. You will have to show us the real code for us to help you identify the specific problem, but if Promise.all() is not waiting for a transition promise, then that promise must not be properly chained into the array of promises that Promise.all() is waiting on.
Specifically, we need to see the code behind this part of your pseudo-code:
array of update.then(transition) promises
to see exactly how transition() is involved in creating that array of promises.
As always, if you show us your REAL code rather than just pseudo-code, we can help find the source of the actual error in programming logic.
A possible scenario is that you are using JQuery < version 3, and the call to authPromise() returns a JQuery promise. This would mean all the promises returned by then in the promise chain returned by Utility.promiseChain are JQuery promises. The last time I checked, older versions of JQuery do not recognize foreign library promises, including those returned by native Promise constructors, as a promise and will fulfill a JQuery promise resolved with one without waiting for it to be settled.
It is possible that the promise object returned by Promise.all in
.then(function() { return Promise.all( // ...
is being used to fulfill the promise returned by then without waiting for it to be settled.
In short you can't resolve an older version of JQuery promise with an ES6 promise and produce the effect of resolving a promise with a promise.
Potential solutions:
Upgrade to JQuery 3 (you lose support for old versions of IE but these don't support Promise anyway). Recommended if you can do it.
Convert all promise usage to ES6 style promises and convert any JQuery promises that are being passed around to ES6 promises before use by calling Promise.resolve( jqPromise)
Write the equivalent of Promise.resolve in reverse to convert an ES6 promise into a JQuery promise. I would rate this as possible but a huge hack backwards in the wrong direction.

Is promise constructor function necessary or can it be avoided?

According to Promise - Javascript | MDN,
The constructor is primarily used to wrap functions that do not
already support promises.
At a low level, the functions that already support promises would
be doing this right i.e constructing a promise using Promise and returning it back?
Is there a better way to create a promise other than using the Promise constructor function?
Eventually, you have to register a callback somewhere right? I mean you can't avoid having a callback that at-least resolves? In other words, we have to wrap it like this somewhere in the library correct?
At the lowest level? Yes, probably.
Depends on the context. If the value you want to resolve the value to is already available, then you'd use Promise.resolve(theValue). If you want to wait for multiple promises you'd use Promise.all(allThePromises). And of course every call to .then returns a new promise.
If you want to do anything with the value of a promise, then yes, you have to pass a callback to .then. There is no other way to get the value.
Having said all that, ES2017 introduced async functions which are basically syntactic sugar for promises. async functions always return a promise and you can use await to unwrap promises. Example:
async function get() {
return await Promise.resolve(42);
}
get().then(console.log);
At a low level, the functions that already support promises would be doing this right i.e constructing a promise using Promise and returning it back?
The eventual goal is that even the low-level APIs within Node.JS will be using the Promise syntax so there will be no need for callbacks. The PromiseJS community considers the constructor syntax to be a polyfill for this eventual behavior. Source.
In practice, this is obviously not the case. Browsers, Node.JS and other Javascript runtime environments make heavy use of callbacks, and so the Promise constructor is used.
Is there a better way to create a promise other than using the Promise constructor function?
Yes- but this depends on application.
Most obviously, if you are using an API which already returns a promise, you can use .then() and .catch() syntax to chain promises together.
There are also a number of libraries which extend the default Promise functionality and provide convenience methods for increased performance and readability. For instance, Bluebird (a common PromiseJS library) offers a way to evaluate the result of multiple promises created concurrently for faster overall runtime.
You can also construct Promises from other paradigms which simplify code- for instance Promise.Promisify which converts a callback function into a Promise one, or Observable.toPromise which converts Observables to promises.
Eventually, you have to register a callback somewhere right? I mean you can't avoid having a callback that at-least resolves? In other words, we have to wrap it like this somewhere in the library correct?
Similar to the answer to your first question, this is a symptom of code currently using the callback paradigm. If all libraries used Promises on a lower level, this wouldn't be the case.
At a low level, the functions that already support promises would be doing this right i.e constructing a promise using Promise and returning it back?
Yes. Maybe. At a low level, we don't know how functions that already support promises do construct those. Imagine what the Promise constructor itself uses to construct promises…
Is there a better way to create a promise other than using the Promise constructor function?
No, there's no other way accessible to JS. But as MDN notes, you should rarely ever need to do this yourself, and rather just use other functions that already create promises for you (which by themselves of course go through the Promise constructor somehow).
Eventually, you have to register a callback somewhere right? I mean you can't avoid having a callback that at-least resolves?
Not necessarily. At a low level, you could also register any arbitrary data structure that allows to resolve a promise, this does not necessarily need to be a callback function. (It is however indeed equivalent in power to registering the resolve callback function).
For example the native implementation of the fetch API (afaik the first native API that directly returns promises) will hardly create JS callback functions anywhere to resolve its promises.

Does "resolve" consistently mean something distinct from "fulfill"?

(Related but not quite the same: JS Promises: Fulfill vs Resolve)
I've been trying to wrap my head around Javascript promises, and I'm struggling with the basic notions of resolve and resolved, vs. fulfill and fulfilled. I have read several introductions, such as Jake Archibald's, as well as browsing some relevant specs.
In States and Fates (not quite an official spec, but referenced as an authoritative document written by one of the spec authors), fulfilled is a state while resolved is a "fate" (whatever that is -- but they're clearly distinct):
Promises have three possible mutually exclusive states: fulfilled,
rejected, and pending.
A promise is fulfilled if promise.then(f) will call f "as soon as
possible."
and
A promise is resolved if trying to resolve or reject it has no effect,
i.e. the promise has been "locked in" to either follow another
promise, or has been fulfilled or rejected
In particular, resolved encompasses both fulfilled and rejected (and locked in). The "opposite" (or directly corresponding function) to reject is fulfill, not resolve; resolve includes reject as one of its possibilities.
Yet the spec refers to the first argument to the then() method (or its corresponding abstract concepts) using both fulfill and resolve:
25.4: A promise p is fulfilled if p.then(f, r) will immediately enqueue a Job to call the function f.
25.4.1.1: [[Resolve]] A function object The function that is used to resolve the given promise object.
25.4.1.3: Set the [[Promise]] internal slot of resolve to promise.
Set the [[AlreadyResolved]] internal slot of resolve to alreadyResolved. [Then immediately after, reject is used in an exactly corresponding way.]
25.4.5.3: Promise.prototype.then ( onFulfilled , onRejected )
Maybe one of the most crucial is
25.4.4.5 Promise.resolve ( x )
which MDN describes as follows:
The Promise.resolve(value) method returns a Promise object that is resolved with the given value. If the value is a thenable (i.e. has a "then" method), the returned promise will "follow" that thenable, adopting its eventual state; otherwise the returned promise will be fulfilled with the value.
There is no mention of the Promise.resolve() method having the potential to reject. Furthermore, there is a Promise.reject() method, but no Promise.fulfill() method. So here, the counterpart to reject is resolve, instead of fulfill.
Granted, there might be no guaranteed correlation between the "fate" term resolved, and the method (or verb) resolve. But it would be (is?) really misleading and confusing to have resolve() put a promise into a specifically fulfilled state, when the terms fulfilled and resolved have carefully been defined to have distinct meanings.
Is that what has happened here... the right hand didn't know what the left hand was doing, and we ended up with the documents that are supposed to be the guiding lights of the movement using terms in inconsistent ways? Or is there something I'm missing, and resolve is actually a more appropriate term than fulfill for what the resolve() method does?
I don't mean to come across as critical of the document authors. I understand how, with a widely-distributed group, over history, it's difficult to get all the terms to be used consistently across all documents. My purpose here, in digging into the terminology and phrasing of these documents, is to understand the terms accurately -- which includes knowing the limits of how precisely terms like fulfill and resolve can really be distinguished. Jake Archibald admits that he sometimes gets the terms mixed up. That's a very helpful admission to noobs like me who are trying to make sense of terminology! Thank you, Jake, for being vulnerable. :-) My purpose in asking this question is to find out, which definitions or usages of those terms are reliable? Or should I conclude that resolve is sometimes used specifically to mean fulfill, and sometimes fulfill/reject/lock in, even in the most authoritative documents?
I'm struggling with the basic notions of resolve and resolved, vs. fulfill and fulfilled.
Have a look at What is the correct terminology for javascript promises. Yes, they're sometimes mixed up, but let's try to ignore that.
Yet the spec refers to the first argument to the then() method (or its corresponding abstract concepts) using both fulfill and resolve. Did we end up with the documents that are supposed to be the guiding lights of the movement using terms in inconsistent ways?
No, there is no inconsistency here, the terms in the spec are accurate.
resolve is not the opposite of reject, and the onFulfilled callback does not exactly correspond to resolving.
Or is there something I'm missing, and resolve is actually a more appropriate term than fulfill for what the resolve() method does?
Yes. The problem is that you can resolve with a promise (or in general, a thenable, i.e. any object with a then method), and instead of fulfilling with that object the resolved promise will try to fulfill with the thenable's result. Or when the thenable has (will have) an error, it will reject with that as the reason.
There is no mention [in MDN] of the Promise.resolve() method having the potential to reject.
Actually there is: "the returned promise will "follow" that thenable, adopting its eventual state". If that eventual state is the error state, then the returned promise will reject as well.
There is a Promise.reject() method, but no Promise.fulfill() method. So here, the counterpart to reject is resolve, instead of fulfill.
Yes, ES6 promises are lacking a Promise.fulfill method. This is a bit inconsistent and confusing at first, but was done for a good reason: It prevents you from having a promise that is fulfilled with another promise. You can only resolve ES6 promises, and when you pass in a promise it will take its result not the promise object by itself.
This is pretty useful, but can be pretty inconvenient as well. There are libraries that do it better and allow this case, they're so-called "algebraic promises" (which you can reason about a lot better). Creed is a good example of that, and its Promise.of method is a real counterpart to Promise.reject.
Let's add emphasis somewhere else in one of your quotes :
A promise is resolved if trying to resolve or reject it has no effect, i.e. the promise has been "locked in" to either follow another promise, or has been fulfilled or rejected
reject() will change your Promise and all the prior-chained ones status to rejected.
While resolve() will lock your current Promise, but only the fulfillment of the resolving callbacks will set its status to fulfilled. As long as everything is not finished, your Promise will still be 'pending'.
e.g If you do chain your Promise, and that during the chain, an error is thrown, then the state of your Promise is set to 'rejected'.
var p = new Promise((resolve, reject) => {
resolve(); // here p is resolved, we can't call resolve() or reject() anymore
}).then((e) => { // chain it
return new Promise((resolve, reject) => {
console.log(p); // 'pending' because it's still chained
reject('whatever') // this one throws an error and breaks the chain
})
}).then(() => console.log('passed')); // won't happen
setTimeout(() => console.log(p, "please check in your browser's console"), 1000); // rejected
So even if you are resolve()-ing the current operation of your Promise, you can't know what will happen after, so you can't know if at the end it will be fulfilled or rejected.

Reactjs promises, how should we use it?

I've been reading a lot about React for the last 3 days, but I don't see much information about the use of promises, so I have that concern.
Is there any library for this?
How should I use promises in React?
React doesn't come with a promise library baked in like Angular with $http. You will have to find your own.
A few you can try:
Bluebird (personal recommendation)
jQuery's $ajax
Native promises (unless you actually have to support IE): http://caniuse.com/#feat=promises
Promise object is used for handling asynchronous computations which has some important guarantees that are difficult to handle with the callback method (the more old-school method of handling asynchronous code).
A Promise object is simply a wrapper around a value that may or may not be known when the object is instantiated and provides a method for handling the value after it is known (also known as resolved) or is unavailable for a failure reason (we'll refer to this as rejected).
Using a Promise object gives us the opportunity to associate functionality for an asynchronous operation's eventual success or failure (for whatever reason). It also allows us to treat these complex scenarios by using synchronous.
To see more at : https://www.npmjs.com/package/react-promise

Categories