JavaScript is a language of the Web. This series of articles will talk about my observations learned during my decade of software development experience with JavaScript.
Introduction
A Promise is an asynchronous operation that has not completed now, but will complete in the future. ES6 has adopted promises implementation as native APIs. Promise gives us guarantee to return the value in future. Promises are not like events where you need to bind the event with a particular method.
Creating a promise
The way to create a Promise is by using "new Promise" constructor, which accepts two callback functions as parameters. The first typically named resolve is a function to call with the future value when promise is ready. The second typically named reject is a function to reject the Promise if it cannot resolve the future value.
Syntax
As per MDN, below is the syntax:
new Promise( /* executor */ function(resolve, reject) { ... } );
Executor: A function that will be passed to other functions via the arguments resolve and reject.
Sample code
- var p1 = new Promise(function(resolve, reject)
- {
- if ( )
- {
- resolve( );
- }
- else
- {
- reject( );
- }
- });
Let us see what happens at Browser after we trigger above code.
- When code executes “new Promise”, it starts from below state
The first state of Promise is “pending”.
- After Promise is fulfilled then it changes to:
The second state of Promise is “fulfilled” or a promise is “rejected” if it’s not fulfilled.
Summary of Promise states:
- pending: Initial state, not fulfilled or rejected.
- fulfilled: Meaning that the operation completed successfully.
- rejected: Meaning that the operation failed.
Prototype promise methods
After a Promise is created, we need to pass around value of this Promise. Inorder to consume a Promise value we attach a handler using via below methods.
Two methods of Promise are associated with constructor prototype Promise.prototype these are:
then() method
It returns a promise with two arguments, i.e., onFulfilled, on Rejected
- onFulfilled: a callback function called when promise is fulfilled.
- onRejected: a callback function is called when promise is rejected.
Example –it will print “Fulfilled!” because we’ve set flag = true,
- var flag = true;
- var p1 = new Promise(function(resolve, reject)
- {
- if (flag)
- {
- resolve("Fulfilled!");
- }
- else
- {
- reject("Rejected!");
- }
- });
- p1.then(function(value)
- {
- console.log(value);
- }, function(reason)
- {
- console.log(reason);
- });
catch() method It returns a promise and deals with rejected cases only. If you pass null or undefined in .then() method first argument it .then() method behaves like .catch() method.
Example- Below code will print “Rejected!”
- var flag = false;
- var p1 = new Promise(function(resolve, reject)
- {
- if (flag)
- {
- resolve("Fulfilled!");
- }
- else
- {
- reject("Rejected!");
- }
- });
- p1.then(function(value)
- {
- console.log(value);
- }).catch(function(reason)
- {
- console.log(reason);
- });
Example - Chaining promises via .then() method.
As .then(), .catch() methods return Promise so we could chain these [please refer Voice of a Developer JavaScript Chaining part 16 to understand Chaining].
Example- chaining of .then() method and incrementing counter.
- var counter = 0;
- var p1 = new Promise(function(resolve, reject)
- {
- resolve(counter);
- });
- p1.then((value) =>
- {
- console.log('Counter: ' + ++counter);
- }).then((value) =>
- {
- console.log('Counter: ' + ++counter);
- }).then((value) =>
- {
- console.log('Counter: ' + ++counter);
- }).catch(function(reason)
- {
- console.log(reason);
- });
Output
Promise methods
Promise.all() –When you are working with multiple promises, this function is really helpful. Once all Promises are resolved or rejected, it returns Promises.
- var p1 = new Promise(function(resolve, reject)
- {
- var counter = 0;
- resolve(++counter);
- });
- var p2 = new Promise(function(resolve, reject)
- {
- resolve("counter 2");
- });
- var p3 = new Promise(function(resolve, reject)
- {
- setTimeout(resolve("Promise 3"), 5000);
- });
- Promise.all([p1, p2, p3]).then(function(values)
- {
- console.log(values);
- }).catch((val) =>
- {
- console.log(val);
- });
Once all Promisesp1, p2, p3 are fulfilled.then() method is called. The above code .then()will execute after 5 seconds when all Promises are resolved (after setTimeout).
If any promise returns reject, then it will return “rejected”.
Promise.race() – It returns a Promise which resolve or reject first. It accepts an iterable of Promises and works like OR condition.
- var p1 = new Promise(function(resolve, reject)
- {
- setTimeout(resolve, 1500, "resolved - will not get printed");
- });
- var p2 = new Promise(function(resolve, reject)
- {
- setTimeout(reject, 100, "rejected - printed");
- });
- Promise.race([p1, p2]).then(function(value)
- {
- console.log(value);
- }, function(reason)
- {
- console.log(reason);
-
- });
Load XMLHttpRequestfiles The use of Promises is by using XMLHttpRequestAPI asynchronously. It loads file in background, example: it will load two JSON files via XHR requests:
automobile.json - {
- "automobile": [
- {
- "vehicle": "car",
- "engine": "1200cc"
- },
- {
- "vehicle": "bike",
- "engine": "200cc"
- },
- {
- "vehicle": "jeep",
- "engine": "2000cc"
- }]
- }
employee.json
- {
- "employees": [
- {
- "firstName": "John",
- "lastName": "Doe"
- },
- {
- "firstName": "Anna",
- "lastName": "Smith"
- },
- {
- "firstName": "Peter",
- "lastName": "Jones"
- }]
- }
Script.js - varary = ['http://localhost/automobile.json', 'http://localhost/employee.json']
- var p1 = new Promise(function(resolve, reject)
- {
- letsrcurl = getJSON(ary[0], resolve);
- });
- var p2 = new Promise(function(resolve, reject)
- {
- letjson = getJSON(ary[1], resolve);
- });
- functiongetJSON(json, resolve)
- {
- varxmlhttp = new XMLHttpRequest(json);
- xmlhttp.open("GET", json);
- xmlhttp.send();
- xmlhttp.onload = function()
- {
- if (xmlhttp.status === 200)
- {
- resolve(xmlhttp.responseText);
- }
- }
- };
- Promise.all([p1, p2]).then((val) =>
- {
- document.getElementById('div2').innerHTML = val;
- });
Output: it will load data of ‘val’ into ‘div2’ of HTML.
Promises Advantages
- It gives us ability to write async code synchronously.
- You can handle via handler whether its resolved or rejected
- Solve problem of code pyramids, ex-
- step1(function(value1)
- {
- step2(value1, function(value2)
- {
- step3(value2, function(value3)
- {
- step4(value3, function(value4)
- {
-
- });
- });
- });
- });
This is solved and simplified via Promise prototypal methods & chaining.
- var p1 = new Promise().resolve('resolve');
- p1.then((value) =>
- {
- console.log(value);
- }).then((value) =>
- {
- console.log(value);
- }).then((value) =>
- {
- console.log(value);
- }).then((value) =>
- {
- console.log(value);
- });
Libraries providing Promises
Promises are supported via different libraries Q, AngularJS, BlueBird etc. There are many libraries providing promises as an abstraction on top of JavaScript Native Promises API, e.g.
Q.js- var functionA = function()
- {
- return "ret A";
- };
- var functionB = function()
- {
- return "ret B";
- };
- var promise = Q.all([Q.fcall(functionA), Q.fcall(functionB)]);
- promise.spread(finalStep);
AngularJS -
- $http(
- {
- method: 'GET',
- url: '/someUrl'
- }).then(function successCallback(response)
- {
-
-
- }, function errorCallback(response)
- {
-
-
- });
It generates a HTTP request and returns a response.
Summary
Please share your feedback / comments.
<< Voice of a Developer: JavaScript Web App Performance Best Practices - Part Thirty One