What is a promise object? [closed] - javascript

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
Having started learning Ember, I get confused whenever there is a reference to Promise Object. I am aware of objects e.g. instance of class X or a JSON object. For instance, when somebody says that method m returns a JSON object then I know to expect key-value pairs. How do I relate this understanding to promise objects? Is a promise object a value (could be array, string, number, JSON object, etc.)?
What should I expect if a method returns a promise object?

A promise is a new Object type of EcmaScript 6 (ES6), for which there are numerous polyfills and libaries (i.e. implementations for ES5 JavaScript engines), and allows (among other benefits) to get out of the infamous callback hell, and to write and read asynchronous code easily.
A promise can have one (and only one) of these three status:
pending
fulfilled
rejected
If the promise is rejected or fulfilled, it also has a settled status.
Basically, it is an object that has a then property (amongst others), which is a function that takes at least one function as a parameter, and can take two: the first one will be invoked if the promise returns a fulfilled status, and the second one will be invoked if the promise returns a rejected status
The then function returns itself another promise, so promises are chainable.
Promise objects are rather more complicated than what I just wrote here, but it was just to give you a start.
BTW, you may have used a promise-like object (note the -like suffix) if you use jQuery : $.ajax() returns a promise-like object (those are called thenables) that has a done (and a then) property which is a function that accepts a function as the parameter that seems like a fulfilled function (which normally takes only one argument). Promise objects also may have a done function property (not standardised, AFAIK, but almost all the polyfills and the libraries implement it), which acts like a then function, only it does not return a promise (hence the name: if you are done with the promise, then use done(), but if you need to do somehting with the result of the promise, use then()).
e.g.: you may have seen or written something like this:
$.ajax({url: '/path/to/html/piece'})
.done(function(data) {
$('whateverSelector').html(data);
});
But what jQuery calls promises, even if they are thenables, does not fulfill the promise spec.

Promise object is what it's name says it is - a promise. In frontend frameworks like Ember and Angular promise is an object returned by an asynchronous call. This call instead of blocking the whole system returns you a promise, which will eventually contain the data the asynchronous call returns.
Promises have an event called resolve, which is triggered when the response come. That's why promise objects have method usually called then. You can use it like this (after Ember.js docs):
var promise = fetchTheAnswer();
promise.then(fulfill, reject);
function fulfill(answer) {
console.log("The answer is " + answer);
}
function reject(reason) {
console.log("Couldn't get the answer! Reason: " + reason);
}
When your request is fulfilled the promise will call the method fulfill with answer (response) as an argument, and when the request is rejected (ie. when the resource doesn't exist) it will call method reject with reason (error) as an argument.
Such objects are similar to objects in other OO languages like java - they contain both data and methods you can call on them.

Related

Why does Promise.all() tigger Array.prototype.then if defined?

Having the following pice of code...
const array = [
Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)
];
Array.prototype.then = function () {
console.log('Why does this gets triggered?');
}
Promise.all(array)
.then(result => console.log(result))
Why does Promise.all() by itself calls my .then() proto function on the Array?
Of course it must call .then() for each of the elements in the array. That’s obvious. But what is the purpose of doing it over the Array itself?
This behavior is happening on V8
To consider: If you change Promise.all() to Promise.race() this does not happen.
I'm not saying this is a mistake. I just want to understand the reason. If you can quote the EcmaScript specification on the answer I would really appreciate.
Update:
I know Promise.all() returns an array but wrapped on a promise. That is obvious too. If you remove the .then() like...
Promise.all(array)
it still executes the .then()method.
When a resolve() is called, and the value passed to it has a .then property that refers to a function, the normal Promise mechanism will invoke that function. In this case, internal to Promise.all() an array of resolution values is built as each Promise in the source array is resolved. When that finishes, the innards of Promise.all() will call its own resolve(), passing in the array of resolved values.
Well that array will also have a .then() value, inherited from the Array prototype. Thus that resolve() call will invoke the .then() method just like any other Promise resolution would.
Promise resolve() in the spec

Return an object with a "then" function within "Promise.then()"

Within my Node.JS application I have written a function (findByReference) that goes to a database and asynchronously yields a fetched database row. I have written this function using Promises. Additionally, I have written an implementation of the Maybe monad and want my findByReference function to yield an instance of Maybe.
My code looks like the below:
findByReference(r)
.then(raw => raw ? Just(raw) : Nothing())
.then(row => {
(row instanceof Maybe) === true;
});
Without going into what Just and Nothing mean, the implication of this (because of how I've written Maybe) is that the row variable in the above code has a function on it called "then". To cut a long story short, it appears that Javascript is getting confused and is for some reason automatically calling MY "then" and instead of passing the Maybe is actually passing to the callback whatever MY "then" returns as the value of row. This is obviously leading to all manner of weird behaviour. If I simply remove the "then" function from my object then it all works as expected.
I am aware that if a Promise.then returns another Promise, then execution will pause until that promise is resolved. I have been unable to find any official documentation to back this up, but is it the case that this decision is simply based on the existence of a "then" function (the closest I have found is this https://developers.google.com/web/fundamentals/primers/promises which refers to the return value as "something Promise-like"). If this is the case, it would be my understanding that "then" as a function name is basically a reserved word in Javascript? I have seen other implementations of Maybe (such as this one https://www.npmjs.com/package/data.maybe) that use the word "chain" for a similar thing - I wondered if this is why?
Can anyone shed any light on if my deduction here is correct and if so is there any workaround I can use other than renaming my function?
FYI the only other SO question I've found that touches this problem is this one - Resolve promise with an object with a "then" function - but since that is angular-specific I don't believe this is a duplication.
Thanks in advance!
...the row variable in the above code has a function on it called "then". To cut a long story short, it appears that Javascript is getting confused and is for some reason automatically calling MY "then"...
It's not confused. :-) This is the definition of how promises work. JavaScript's promises work according to the Promises/A+ specification, which uses this 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.
If you have an object passing through a promise chain that's a thenable but not a promise, it's incompatible with promises.
So yes, in a sense, the then property of objects passing through promise chains is "reserved" by the Promises/A+ spec. You'll need to wrap your raw value in an object that doesn't have a then (and then unwrap it later). Or if you can, rename then in your design to remove the conflict.

Node: Is behavior well-defined for Promise.all with non-Promise values?

The docs for Promise.all() describe the argument as an array of Promises. Is behavior defined if some (or all) of the elements in the array are non-Promise values? For example, in Node 6.10.2:
Promise.all([1, 2, 3]).then(
res => console.log(res)
);
Prints [ 1, 2, 3 ], as expected. Is this behavior (where Promise.all resolves with the same values that it was called with) guaranteed in Node?
Promise.all() is specified in the ES6 specification.
It appears that section 24.4.4.1.1 in that ES6 specification at step 6.i describes how each item in the iterable passed to Promise.all() is passed to a promise constructor (essentially calling Promise.resolve(item)) so that any non-promise gets wrapped in a promise that will resolve itself on the next tick.
You need to follow the overall context of how these steps work to fully understand, but the specific 6.i step is this:
Let nextPromise be Invoke(constructor, "resolve", «‍nextValue»).
Where constructor (in this context) is Promise and Invoke() is calling the resolve method on it - so it's essentially doing:
let nextPromise = Promise.resolve(nextValue);
Which is how each item in the iterable is wrapped in a promise if it wasn't already a promise.
Then, later in step 6.r, it does this:
Let result be Invoke(nextPromise, "then", «‍resolveElement, resultCapability.[[Reject]]»).
Which is where it calls .then() on nextPromise which will now work fine even if the item in the iterable was not originally a promise because it has been wrapped in a new promise.
And, in 24.4.4.5 the description of Promise.resolve(x) is as follows:
The resolve function returns either a new promise resolved with the passed argument, or the argument itself if the argument is a promise produced by this constructor.
So, you can see that the value is wrapped in a new promise if it is not already a promise.
Is this behavior (where Promise.all() resolves with the same values that it was called with) guaranteed in Node?
Yes, if the values are not promises, then it will resolve with an array of the same values. It will be a different array, but the same values in the new array. If any of the values are promises, then obviously, the final array contains the resolved value of that promise. This is guaranteed by the specification.

Can I clone a Promise?

I have an asynchronous function that returns a promise. The operation should only be performed once. I want all callers of that function to get back the same Promise, but I don't want .catch()es of one caller to affect another caller. Can I clone a promise, or implement this in another way?
but I don't want .catch()es of one caller to affect another caller.
They never1 do (unless you've chained the callbacks, which you don't).
I want all callers of that function to get back the same Promise
Just do it. Promises are immutable values2.
Can I clone a promise?
If you really need3 a distinct object that will follow the original promise (fulfill when it fulfills or reject when it rejects), you can use the then method without arguments:
var clone = promise.then();
console.assert(clone !== promise);
1: Assuming you use a proper promise library. I think I can remember a case of a library (old jQuery?) where then callback results changed the state of the promise.
2: In their resolving behaviour, at least. Every promise is still just an object of course.
3: You don't. You really should not. I'm just answering the title question, but you should stop doing weird stuff.

Accessing a previously fulfilled promise result in a promises chain [duplicate]

This question already has answers here:
How do I access previous promise results in a .then() chain?
(17 answers)
Closed 8 years ago.
What is the correct pattern, when coding with promises, to access data coming from long before in a chain of promises?
For example:
do_A.then(do_B).then(do_C).then(do_D).then(do_E_WithTheDataComingFrom_A_And_C_OnlyWhen_D_IsSuccesfullyCompleted)
My current solution: passing along a single JSON structure through the chain, and let each step populate it.
Any opinion about that?
I don't think there's one "correct" pattern for this. Your solution sounds neat, however, it's a bit tightly coupled. It may work great for your situation, but I see a few problems with it as a general pattern:
Participating steps need to agree on the structure of the collector object.
Every step needs to participate in at least the forwarding of the object, which can get tedious if the chain is long and the need for previous data occurs sporadically. This is also inflexible to insertion of steps not written by you (chaining doesn't always happen linearly).
Said differently: Unless do_A|B|C|D and do_E are under your control, you'll need to wrap them with boilerplate to store off your collector object in a closure and convert to and from the functions' natural inputs and results, since the functions wont be "in on" your pattern.
On the other hand, if the functions are in on it, then the data-dependencies between the steps have effectively become hidden inside the functions. This may look clean, but it could become a maintenance problem. For example: if this is a team project, then someone might think they can re-order your steps, absent any no clue in the call-pattern what inputs do_E requires.
I would suggest a more straightforward approach using closures:
var a, c;
do_A()
.then(function(result) { a = result; return do_B(); })
.then(do_C)
.then(function(result) { c = result; return do_D(); })
.then(function() {
return do_E_WithTheDataComingFrom_A_And_C_OnlyWhen_D_Succeeds(a, c);
})
.catch(failed);
There's no collector object to define; do_A|B|C|D and do_E can be generic functions without knowledge of any pattern; there's no boilerplate unless returned data is relied on (do_B and do_D); and the data-dependencies (a and c) are explicit.
Yes, this is the correct way to chain state with actions.
Chaining .then statements is very common and is usually our building block when piping things around. It's at the very core of promises.
What you're doing is both correct and idiomatic.
For the curious spirit let's show this.
In order to verify this - we can check the promises specification.
We want to verify that:
It chains
In the case of a rejection, it doesn't call the handler in the chained then
It rejects the next promise returned from then with the same reason
It executes in sequence passing return value.
Let's verify these in order, using the specification - in particular .then:
1. It chains
7.1 then must return a promise [3.3].
Great, let's verify that it also chains on fullfillment
If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure >[[Resolve]](promise2, x).
Great, so we know that when our promise resolves or rejects then our then handler is called with the appropriate parameter. So .then(do_A).then(do_B) will always work assuming do_A resolves.
2. In the case of a rejection, it doesn't call the handler in the chained then
7.iv. If onRejected is not a function and promise1 is rejected, promise2 must be rejected with the same reason.
Great, so it rejects and calls onRejected if it's there, if it doesn't it chains.
3. It rejects the next promise returned from then with the same reason
We just covered that in 2.
4. It executes in sequence passing return value.
That is again
If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
So, if you set onFulfilled it'll run the resolution process. The resolution process itself dictates:
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.
If/when resolvePromise is called with a value y, run [[Resolve]](promise, y).
Where y is the return value of x.
Great! so it works.

Categories

Resources