Understanding JavaScript promise object
Promise execution is asynchronous, which means that it's executed, but the program won't wait until it's finished to continue with the rest of the code.
Basically, your code is doing the following:
- Log 'Hi'
- Create a promise
- Execute the promise
- Log 'zami'
- Promise is resolved and logs 'There'.
myPromise.then(function (result) {
// Resolve callback.
console.log(result);
console.log('zami');
}, function (result) {
// Reject callback.
console.error(result);
});
Having trouble fully understanding Promises in Javascript
Have you ever been to a pizza restaurant, where you order your pizza and then you don't get the pizza immediately, but you get a buzzer device that will warn you when your pizza is ready? That's exactly what a Promise
is.
The function that you pass to the constructor of Promise
is the cook that is going to prepare the pizza. The cook takes two parameters, which are functions. When the cook has finished the pizza, it will call the resolve
function. If something goes wrong and the pizza cannot be finished, it will call the reject
function.
Who calls resolve and reject?The function that you pass to the constructor of
Promise
(the cook) does. It's right there in your code:if (bool) {
resolve('Pass'); // Call the resolve function
} else {
reject('Fail'); // Call the reject function
}
You supply the actual functions to call by calling then(...)
and catch(...)
on the Promise
object.p.then(function(val) { // <= This function is the actual resolve function
console.log(val);
}).catch(function(val) { // <= This function is the actual reject function
console.log(val);
});
It might be easier to understand by using a concrete example like with the cook and pizza than when you use abstract concepts:function pizzaCook(resolve, reject) {
let bool = false;
if (bool) {
resolve('Pizza is ready!');
} else {
reject('Sorry, the oven is broken!');
}
}
var p = new Promise(pizzaCook);
function letsEat(msg) {
console.log('Great, I can eat now, the cook said: ' + msg);
}
function stayHungry(msg) {
console.log('Oh no, I will stay hungry, because: ' + msg);
}
p.then(letsEat).catch(stayHungry);
What is 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
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. difficult to understand promise and asycn... ;
We have Promise and Observables to deal with the asynchronous nature of functions or app and yes Async always returns a promise while obervables can be returned by both synchronous and Asynchronous functions. A promise is followed by two keywords,
const promise = FooPromise((resolve,reject) = > {
revolve("i am resolve");
reject("i am reject");
)
after this we define what to do if our promise is resolved or rejected by these keywords respectively..then((resolveMessage) => {
console.log(resolveMessage);
}
.catch((catchMessage) => {
console.log(CatchMessage);
}
How JavaScript promises work behind the scenes
The following is a simplified implementation of the built-in Promise class. catch
and finally
have not been implemented.
The function supplied to the Promise constructor is called the executor function, and is invoked immediately and synchronously.
Every promise has a method .then
, enabling the chaining of promises.
Functions supplied to .then
are always invoked asynchronously on a microtask (note use of queueMicrotask
below).
Every time .then
is called, a new promise is created and returned.
.then
can be called more than once on the same promise, creating a multicast of the result of the promise, and a branching of the promise chain.
A promise can be in one of three states: pending, fulfilled, or rejected. State transitions are unidirectional: you cannot move from fulfilled or rejected, back to pending.
If a promise is resolved with another promise, then the two promise chains are joined and the outer promise takes on the status of the inner promise (which could be pending), until the inner promise resolves.
function Promise(executor) { if (!executor) throw "Promise executor undefined" let status = "pending", value, thenQ = []
const then = onFulfilled => { let resolver // This ensures control does not move to later promises // until prior promises have been resolved. const nextPromise = new Promise(resolve => (resolver = resolve)) // More than one "then" can be registered with each promise. thenQ.push((...args) => resolver(onFulfilled(...args))) return nextPromise }
// We check if the result is a "thenable"; if so, we treat // it as an inner promise, otherwise we simply fulfil with // the result. const resolve = result => result?.then ? result.then(fulfil) : fulfil(result)
// When a promise has been fulfilled, its "thens" can be run. const fulfil = result => (status = "fulfilled", value = result, executeThens(value))
// "Thens" are run asynchronously, on a microtask. const executeThens = value => queueMicrotask(() => thenQ.forEach(el => el(value)))
// The executor is run synchronously. executor(resolve)
return { then, get status() { return status }, get value() { return value } }}
// Chainingnew Promise(resolve => { console.log('Waiting for step 1...') setTimeout(() => resolve("One, two..."), 1500)}).then(result => new Promise(resolve => { console.log('Waiting for step 2...') setTimeout(() => resolve(`${result}three, four`), 1500)})).then(result => console.log(`Chaining result: ${result}.`))
// Branchingconst p = new Promise(resolve => { console.log('Waiting for step a...') setTimeout(() => resolve("Alpha, Bravo..."), 1500)})
p.then(result => new Promise(resolve => { console.log('Waiting for step b1...') setTimeout(() => resolve(`${result}Charlie, Delta`), 1500)})).then(console.log)
p.then(result => { console.log('Waiting for step b2...') return `${result}Echo, Foxtrot`}).then(console.log)
Understanding JS Promises
About Promise resolution
The thing you're witnessing here is called recursive then
able resolution. The promise resolution process in the Promises/A+ specification contains the following clause:
The ES6 promise specification (promises unwrapping) contains a similar clause.onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x)
This mandates that when a resolve
operation occurs: either in the promise constructor, by calling Promise.resolve
or in your case in a then
chain a promise implementation must recursively unwrap the returned value if it is a promise.
In practice
This means that if onFulfilled
(the then
) returns a value, try to "resolve" the promise value yourself thus recursively waiting for the entire chain.
This means the following:
promiseReturning().then(function(){
alert(1);
return foo(); // foo returns a promise
}).then(function(){
alert(2); // will only run after the ENTIRE chain of `foo` resolved
// if foo OR ANY PART OF THE CHAIN rejects and it is not handled this
// will not run
});
So for example:promiseReturning().then(function(){
alert(1);
return Promise.resolve().then(function(){ throw Error(); });
}).then(function(){
alert("This will never run");
});
And that:promiseReturning().then(function(){
alert(1);
return Promise.resolve().then(function(){ return delay(2000); });
}).then(function(){
alert("This will only run after 2000 ms");
});
Is it a good idea?
It's been the topic of much debate in the promises specification process a second chain method that does not exhibit this behavior was discussed but decided against (still available in Chrome, but will be removed soon). You can read about the whole debate in this esdiscuss thread. This behavior is for pragmatic reasons so you wouldn't have to manually do it.
In other languages
It's worth mentioning that other languages do not do this, neither futures in Scala or tasks in C# have this property. For example in C# you'd have to callTask.Unwrap
on a task in order to wait for its chain to resolve. How do promises work in JavaScript?
A promise is basically an object with two methods. One method is for defining what to do, and one is for telling when to do it. It has to be possible to call the two methods in any order, so the object needs to keep track of which one has been called:
var promise = {
isDone: false,
doneHandler: null,
done: function(f) {
if (this.isDone) {
f();
} else {
this.doneHandler = f;
}
},
callDone: function() {
if (this.doneHandler != null) {
this.doneHandler();
} else {
this.isDone = true;
}
}
};
You can define the action first, then trigger it:promise.done(function(){ alert('done'); });
promise.callDone();
You can trigger the action first, then define it:promise.callDone();
promise.done(function(){ alert('done'); });
Demo: http://jsfiddle.net/EvN9P/When you use a promise in an asynchronous function, the function creates the empty promise, keeps a reference to it, and also returns the reference. The code that handles the asynchronous response will trigger the action in the promise, and the code calling the asynchronous function will define the action.
As either of those can happen in any order, the code calling the asynchronous function can hang on to the promise and define the action any time it wants.
Related Topics
Event.Wheeldelta Returns Undefined
How to Keep an JavaScript Object/Array Ordered While Also Maintaining Key Lookups
Catching Errors in JavaScript Promises with a First Level Try ... Catch
How to Set Node_Env to Production/Development in Os X
Is Localstorage.Getitem('Item') Better Than Localstorage.Item or Localstorage['Item']
Remove HTML Comments with Regex, in JavaScript
Decompress Gzip and Zlib String in JavaScript
Where Should I Initialize Pg-Promise
Quickest Way to Pass Data to a Popup Window I Created Using Window.Open()
Regular Expression for Ip Address Validation
Using Raw Image Data from Ajax Request for Data Uri
Why "This" Is Undefined Inside a Fat Arrow Function Definition
How to Detect If JavaScript Files Are Loaded
Professional Jquery Based Combobox Control
Why Does JavaScript Getyear() Return 108
How to Randomly Generate HTML Hex Color Codes Using JavaScript