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. The promise gives us a guarantee to return the value in the 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 the 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 the value of this Promise. Inorder to consume a Promise value we attach a handler using via the 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 the promise is fulfilled.
- onRejected: a callback function is called when the 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 resolves 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 the 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 the ability to write async code synchronously.
- You can handle via handler whether it's resolved or rejected
- Solve the 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 an 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