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

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.

Related

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.

how does promise resolution decide whether to treat a return value as a promise or as a plain value?

Promise resolution "helpfully" does different things depending on whether the return value of resolve() or the return value of the function passed to then() is a promise or not.
Therefore, understanding and predicting the behavior requires knowing precisely what criterion is being used (or is allowed to be used) to determine whether something "is a promise" as I use the phrase in the above sentence, so I'd like to nail that down. I'm interested in Promises/A+ in general, and ES6 native promises in particular.
Looking to https://promisesaplus.com/, it says:
1.1 "promise" is an object or function with a "then" method
whose behavior conforms to this specification.
To see what that means, I look further into 2.2 "The then method", and find that it rests on a set of
behavior criteria making it clearly impossible to decide algorithmically whether a given object
is a promise or not (proof by Halting Problem). And that's fine; it just means the spec
of the "helpful" behavior in question won't be using the term "is a promise" directly.
So, looking further for the spec of the "helpful" behavior, I find 2.3 "The Promise Resolution Procedure".
Surprise! It does use the term "is a promise" directly:
2.3.2 If x is a promise, adopt its state [3.4]
But it saves itself from a descent into meaninglessness in the footnote:
[3.4] Generally, it will only be known that x is a true promise
if it comes from the current implementation. This clause allows
the use of implementation-specific means to adopt the state of
known-conformant promises.
In other words, 2.3.2 didn't really mean "If x is a promise", it really meant (and should have said, IMO) "If x is known to be a promise".
But, if I understand correctly, that part is just a shortcut it's allowed to take if it can prove it's safe to do so.
Moving on, the relevant section seems to be 2.3.3, which I summarize as: treat the return value x like a promise
iff x has a property named "then" which is a function.
So then it all rests on the definition of "x.then is a function".
What does that mean, precisely, for the purposes of someone wanting to implement a conformant library,
or someone wanting to predict what a conformant library must/might do when I use it?
Is it the same as saying typeof x.then === "function"?
Hoping for more clues, I looked into the spec of a supposedly-conformant implementation (or set of implementations), ES6 native promises,
which is linked from the Promises doc on MDN.
I believe the relevant section is 25.4.1.3.2.
It looks like the criterion in question is IsCallable(x.then); following the link to that,
I see to my dismay that IsCallable is not an actual function but rather an "abstract operation",
defined in terms of many other "abstract operations" which are far from simple.
At this point, my hope of seeing any conformant reference code which implements the decision in question appears to be rapidly receding :-(
Backing up to my original question "How does promise resolution decide whether to treat a return value as a promise?",
I think I've boiled it down, as I explained above, to the more specific question: Exactly what does the Promises/A+ spec mean when it says "is a function"?
If that has a simple clear answer (which of course might allow room for variation among implementations),
immediate follow-up questions would be:
Does native promises conform to the simple clear answer?
Why is native promises' implementation of promises/A+'s "is a function" so complicated?
What's a reasonable way for me to ensure that my return value will be treated as a promise as I intend,
or as a plain value as I intend?
So then it all rests on the definition of "x.then is a function". What does that mean, is it the same as saying typeof x.then === "function"?
Yes, exactly that. Barring that accessing x.then throws, so you need to wrap all this in a try block.
Why is native promises' implementation of promises/A+'s "is a function" so complicated?
Because it's spec terminology. "function" is basically defined as a "callable object", and isCallable is just the algorithm to test for that. It's basically the same algorithm that the typeof operator uses to determine whether to return the string "function".
Btw, you'll be interested in Regarding Promises/A+ Specification, what is the difference between the terms "thenable" and "promise"?.

Is a Javascript promise object also a thenable object? [duplicate]

I am checking out the "Promises/A+" Specification, but could not understand the following things:
On Section 1. Terminology,
1.1. "promise” is an object or function with a then method whose behavior conforms to this specification.
1.2. “thenable” is an object or function that defines a then method.
So What is the difference between the terms "thenable" and "promise"?
Also in Section 2.3. The Promise Resolution Procedure,
The promise resolution procedure is an abstract operation taking as input a promise and a value, which we denote as [[Resolve]](promise, x).
So my question is:
Why is it denoted within 2 opening and closing brackets? Is there any convention?
Thank you very much.
So What is the difference between the terms "thenable" and "promise"?
I think the section you've already cited does answer this very well:
A thenable is an object with a then method. Any object.
A promise is an object with a then method (i.e. a thenable) that conforms to the specification.
So far so simple. I think your actual question is: "Why are they distinguished?"
The problem is that by looking at an object you cannot decide whether it is a promise.
You might be able to tell that it is a promise because you can see that its then method is implemented by yourself or someone you trust - the promise library of your choice usually. You would be able to "see" that because the object does inherit from your promise prototype, or you can even compare the method being (referentially) identical to the function you've defined. Or any other inspection method that is sufficient for you.
You might be able to tell that it is not a promise because it has no then method.
But what do you do with an object that implements then, but is not known to be a promise? It's a thenable, and will be handled as such.
The Promises/A+ specification aims for interoperability between promise implementations, and uses the existence of a .then() method for duck typing. It does specify an exact algorithm on how to treat such thenables (that might be promises or at least have similar behaviour) so that you can create an actual, trusted ("known") promise from them.
Why is it denoted within 2 opening and closing brackets? Is there any convention?
Yes, the ECMAScript specifications use this syntax for internal methods and properties:
The names of internal properties are enclosed in double square brackets [[ ]].
Those properties do not actually need to exist, they're purely used to describe what should happen - an implementation must act as if it used them. They are totally abstract operations though.
This is a smart attempt to make it easier for promises to be interoperable between different libraries.
The spec uses the term thenable in just a few places. This one is the most important (empasis mine):
The promise resolution procedure is an abstract operation taking as input a promise and a value, which we denote as [[Resolve]](promise, x). If x is a thenable, it attempts to make promise adopt the state of x, under the assumption that x behaves at least somewhat like a promise. Otherwise, it fulfills promise with the value x.
This will make implementors do a check like:
if (typeof(x.then) === 'function') {
// adopt the state of x
} else {
// fulfill promise with value x
}
If the spec instead said "if x is a promise, then...", how would the implementor know whether x is a promise or not? There's no practical way to make sure if x complies with the Promise spec just by inspecting it.
An implementor (say, library FooPromises might do something like
if (x instanceof FooPromises.Promise) {
// adopt the state of x
} else {
// fulfill promise with value x
}
and it would effectively reject any promises coming from different implementations.
Instead, by using a super-simple definition of thenable in this condition that implementors can easily verify, it's trivial to make this check and you make it possible for implementations to play nice with each other.
For you second question, I'm not sure but my idea would be that a notation [[Resolve]](promise, x) emphasises that it's an abstract operation. If they dropped the brackets and just said Resolve(promise, x), it would somehow imply that implementors should make a real function named Resolve and expose it.
This is not needed - Resolve is not part of the promises' interface; it's just a part of their behaviour that was important enough that it was given a name and a separate section in the docs.

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

Similar pattern to promises/deferred's that support multiple results and cancellation

Similar to the promises pattern I'm looking for an event pattern that avoids needing to pollute objects with addEventListener/etc methods, I want to be able to return an object, that can be cancelled as well as 'resolved' multiple times.
For example, I may write a method that returns an 'interval' object, something like this:
var ticker = createTicker(1000);
var subscription = ticker.then(function() { console.log('tick') });
... later on ...
subscription.cancel();
The key differences here being, similar to a promise the events are standardized, so that I can subscribe without needing to know the event name, however unlike a promise, the "completion" can happen multiple times, and may even be cancelled (this would be equiv of removeEventListener).
I'm interested to see if this is legal with promises, such that the progress handler could be used for multiple callbacks, and the complete handler never used, but more importantly, that there is a concept of unsubscribing from a promise.
If this isn't the case, and promises are specialized to this scenario, is there a standardized pattern for doing what I described?
The ability to cancel can be added to a promise implementation, without breaking the main paradigm of having single-fire success/failure callbacks.
In fact, jQuery already has cancellation for the promise instances that it returns from jQuery.ajax calls:
For backward compatibility with XMLHttpRequest, a jqXHR object will
expose the following properties and methods:
readyState
status
statusText
responseXML and/or responseText when the underlying request responded with xml and/or text, respectively
setRequestHeader(name, value) which departs from the standard by replacing the old value with the new one rather than concatenating the new value to the old one
getAllResponseHeaders()
getResponseHeader()
abort()
You could write a setTimeout wrapper that exposes a promise interface along with an additional cancel method.
However, once you get into the multi-fire territory, I think that is not what promises are intended for. You would have to define a lot of rules and exceptions around how multiple firing will play out alongside regular promise functionality. It doesn't make a lot of sense to me to use promises that way.
Update (based on discussion in comments):
Here's a sample implementation of a promise "proxy" that allows aborting further relaying of the done/fail callbacks:
http://jsfiddle.net/atesgoral/qvtqu/

Categories