A short introduction to JavaScript promises.
Unlike you, JavaScript is single threaded.
It cannot eat lunch and hold a debate about which text editor is the best at the same time.
console.log('Eating lunch');
console.log('Arguing that Atom is better than Sublime');
The above statements will execute in order, one after another, outputting "Eating lunch" and "Arguing that Atom is better than Sublime" to the console. Processing bits of code sequentially is known as single threading.
You are multithreaded. You do not need to wait to finish eating your lunch so you can start a passionate dispute over the superiority of Atom. You can do many things at a time, asynchronously. In JavaScript, you need to wait. Imagine trying to read a file from a disk:
function readJSONSync(filename) {
return JSON.parse(fs.readFileSync(filename, 'utf8'));
}
While you are reading that file, nothing else can happen. You need to wait.
As Alexandre Dumas once said, "All human wisdom is summed up in two words – wait and hope". Well, sort of.
Imagine reading the massive file described above. You want to load all the latest blog posts onto this web page synchronously. The UI and the server won't respond until the function has returned. Wait and hope, right? While providing a gruesome user experience.
All commend patience, but none can endure to suffer – Thomas Fuller
So how do you save yourself from enduring the pain of patience?
The secret of patience is doing something else in the meanwhile – Unknown
So how do you make JavaScript do "something else in the meanwhile"? How do you make it asynchronous?
I don't know where I'm going from here, but I promise it won't be boring – David Bowie
A promise represents the result of an asynchronous operation, a value that you can manipulate in the future.
Sometimes people don't understand the promises they're making when they make them ― John Green
The standard way to create a promise is by using the new Promise
constructor, which accepts a handler that takes two functions as parameters. The first one (resolve
) is a function to call using the future value when it's ready; and the second one (reject
) is a function to call when rejecting the promise, if it can't resolve the future value.
var p = new Promise(function(resolve, reject) {
if (/* condition */) {
resolve(/* value */); // fulfilled successfully
}
else {
reject(/* reason */); // error, rejected
}
});
A promise can be in one of three different states:
After a promise is fulfilled or rejected, it becomes immutable (i.e., its state can never change again).
Keep every promise you make and only make promises you can keep ― Anthony Hitt
A promise can be passed around like a standard value. Think passing it as a parameter or returning it from a function. To use the value just attach the handler .then
to it.
var p = new Promise((resolve, reject) => resolve(5));
p.then((val) => console.log(val)); // 5
.then
takes two parameters - one is the function that will be called in case the promise is fulfilled. The other one is invoked if the promise is rejected.
p.then((val) => console.log("fulfilled:", val))
.catch((err) => console.log("rejected:", err));
One must have a good memory to be able to keep the promises that one makes. ― Friedrich Nietzsche
When working with multiple promises, Promise.all()
comes in handy. It takes an array of promises and returns a promise with an array of fulfilled values. If any of the promises are rejected, the returned promise will be rejected.
var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, "foo");
});
Promise.all([p1, p2, p3]).then(function(values) {
console.log(values); // [3, 1337, "foo"]
});
This can be avoided by using Promise.race()
. This method also receives an array of promises, but unlike Promise.all()
, the outcome of the first promise in the array determines the state of the promise returned by Promise.race()
.
var p3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, "three");
});
var p4 = new Promise(function(resolve, reject) {
setTimeout(reject, 500, "four");
});
Promise.race([p3, p4]).then(function(value) {
console.log(value); // "three"
// p3 is faster, so it resolves
}, function(reason) {
// Not called
});
Learn more about promises here:
Natalia Harateh
Tags: javascript, promises, es6
June 9th 2016