Last updated on September 19th, 2024 at 04:56 am
Today’s websites have become very complex and need to do many things at once. Since JavaScript is a single-threaded programming language, web developers need to use Asynchronous function calls and requests for this purpose. These function calls allow you to perform other tasks in parallel without having to wait for the result of function call. However, they often face difficulties about how to return response from asynchronous call. In this article, we will learn the different ways to receive response from asynchronous function calls in JavaScript.
The Problem
Let us take the example where we have 2 JavaScript functions a() and b(). Function a() waits for sometime before returning ‘hello’ and b() immediately prints ‘hello world’ in console. We save the value returned by a() in data variable and then call b().
function a(){
var result;
i=0;
//takes some time
while(i<10000000){
i++;
}
result = 'hello';
return result
}
function b(){
console.log('hello world');
}
var data = a();
console.log(data);
b();
Here is the output.
hello
hello world
When we execute the above code, data variable has to wait for sometime before it receives the output from a(). On the other hand, b() has to wait even further to be executed. If a() takes too much time, then all subsequent code will have to wait for a() to complete. This is because JavaScript is a single threaded programming language the executes commands sequentially.
To overcome this problem, let us say you decide to make a() asynchronous as shown below and then call b(). We have used setTimeout() function to wait for 5 seconds before setting result variable to ‘hello’. setTimeout() is an asynchronous function that returns control to the subsequent code without making it to wait for result.
function a(){
var result;
setTimeout(function(){result='hello'},5000);
return result
}
function b(){
console.log('hello world');
}
var data = a();
b();
console.log(data);
Here is the output.
hello world
undefined
When we run the above code, you will see that b() function is executed immediately without waiting for the result of a(). But the data variable is undefined. This is because setTimeout() is an asynchronous function that immediately executes the next statement even before its time out value is over and callback function is executed. So a() returns result variable even before it is set to ‘hello’ after 5 seconds. This is the problem commonly faced by web developers.
Available Solutions
At present, there are 3 solutions available for this problem:
- Using Callbacks – Callbacks are functions that are passed as arguments to another function. They can be called from within that function as and when required. It allows you to control sequence of execution in JavaScript.
- Using Promise – A promise is an object that contains the result of an asynchronous operation along with its state – rejected or resolved.
- Using Async/Await – Async makes a function return JavaScript promise while Await makes a function wait for the result of Promise.
In this article, we will learn how to use each of these solutions.
How to Return Response from Asynchronous Call
Let us look at the above approaches one by one.
1. Using Callbacks
Callback is a function that is used as an argument for another function. In asynchronous programming, that allows an asynchronous function to call another function after it has completed processing, without making other code wait. This allows you to control execution sequence.
Here is a simple example to illustrate it.
function a(){
console.log('hello world');
}
function b(data, callback){
console.log(data);
callback();
}
b('hello', a);
Here is the output.
hello world
hello
The above example is meant for synchronous functions. Here is an example to use callbacks in asynchronous function such as SetTimeout.
function a(data){
var result;
setTimeout(function(){console.log(data);},5000);
}
function b(data, callback){
console.log('hello world');
callback(data);
}
b('hello', a);
Here is the output.
hello world
hello
Here function a() is asynchronous as it uses SetTimeout(). While executing b(), we first display ‘hello world’. Only then we call callback() function, which displays a proper output instead of displaying ‘undefined’.
Here is a real world use case of sending request to remote URL, which may take time, and continuing the processing without waiting for its result.
function get_data(callback) {
let req = new XMLHttpRequest();
req.open('GET', my_URL);
req.onload = function() {
if (req.status == 200) {
callback(req.responseText);
} else {
callback("Error: " + req.status);
}
}
req.send();
}
function display_value(data){
console.log(data);
}
get_data(display_value);
The main problem of callbacks is that it makes code complicated, especially in real-world situations where you have complex functions with multiple functions calls in each function. That is why Promise were introduced. Let us learn more about Promise below.
2. Using Promise
Promise basically connects code that processes information and returns values, with code that uses these values.
Here is a simple example of a Promise object that uses 2 callbacks resolve and reject – resolve is called when the result is a success and reject is called when it is an error. You don’t have to define these functions. They are simply placeholders to pass their argument to the code that uses this Promise object later.
let my_promise = new Promise(function(resolve, reject) {
// some processing that takes time
resolve(value_result); // when successful
reject(error_result); // when error
});
Here is the code that uses these values. The then() function uses two optional arguments – first one for success and the second one for failure.
my_promise.then(
function(value) { console.log(value) },
function(error) { console.log(error) }
);
When you run the above code, the value_result passed in resolve() becomes available as value in my_promise.then(). Similarly, error_result becomes available as error in my_promise.then().
Alternatively, you can also use then() and catch() functions to process value and error respectively as shown below.
my_promise.then(
function(value) { console.log(value) })
.catch(
function(error) { console.log(error) });
Here is an example to use Promise to wait for a function result. It waits for setTimeout to complete before displaying its result.
let my_promise = new Promise(function(resolve, reject) {
setTimeout(function() { resolve("hello"); }, 5000);
});
my_promise.then(function(value) {
console.log(value);
});
console.log('hello world');
Here is the output.
hello world
hello
In the above example, even though the promise handler is called before printing ‘hello world’, ‘hello’ is printed only after it, indicating that it is asynchronous.
Here is a real world example where we use Promise to wait for the result of a request, which generally takes some time.
let my_promise = new Promise(function(resolve, reject) {
let req = new XMLHttpRequest();
req.open('GET', my_URL);
req.onload = function() {
if (req.status == 200) {
resolve(req.response);
} else {
reject("Error occurred");
}
};
req.send();
});
my_promise.then(
function(value) {display_data(value);})
.catch(
function(error) {display_data(error);});
function display_data(data){
console.log(data);
}
console.log('hello world');
Here is the output.
hello world
response message from request
When we run the above code, it creates a Promise. In this promise, we create a request object that sends a request to my_url to fetch file/data. Based on the response returned by this request, the Promise handler calls then() or error(). Please note, when the Promise object is created, it immediately returns the control to the subsequent code where we print ‘hello world’. Event though Promise handler is called before displaying this message, it is executed only after response is received.
This allows you to write asynchronous code in a synchronous manner that is easy to understand. Also, it contains separate functions to clearly handle success and error states. Using Promise is one of the best ways to return response from asynchronous call in JavaScript functions.
3. Using Async/Await
Async and Await are two keywords used for implementing Asynchronous functions in JavaScript. Async keyword placed before a function definition will return a promise. Await keyword is placed in an Aync function to basically pause its execution and wait for a promise before proceeding further. Here is its syntax.
async function hello() {
return "Hello";
}
hello().then(
function(value) {console.log(value);},
function(error) {console.log(error);}
);
This is similar to the following code written using Promise.
function hello() {
return Promise.resolve("Hello");
}
hello().then(
function(value) {console.log(value);},
function(error) {console.log(error);}
);
Here is the syntax of Await keyword.
let value = await promise;
Here is a simple example to demonstrate it.
async function hello() {
let my_promise = new Promise(function(resolve, reject) {
resolve("hello");
});
console.log(await my_promise);
}
hello();
console.log('hello world');
Here is the output.
hello world
hello
In the above example, we call hello() function before displaying ‘hello world’ but it is displayed only afterwards. This is because the moment browser encounters async function call, it will immediately return control to the next statement, without waiting for its execution. So ‘hello world’ is displayed. Thereafter, the asynchronous is executed and waited upon due to await keyword. That is why it is printed in the end.
Here is a real world example where we make an asynchronous request for file/data and continue our processing without waiting for the response. When the response it returned, it is processed appropriately.
async function get_data() {
let my_promise = new Promise(function(resolve) {
let req = new XMLHttpRequest();
req.open('GET', my_URL);
req.onload = function() {
if (req.status == 200) {
resolve(req.response);
} else {
resolve("Error occurred");
}
};
req.send();
});
console.log(await my_promise);
}
get_data();
console.log('hello world');
Here is the output.
hello world
response from request
In this example, we wrap the Asynchronous request in Promise using Async keyword and Promise constructor. Since requests can take some time, we use Await keyword to wait for the result of the promise. Otherwise, it would have printed undefined.
Conclusion
In this article, we have learnt 3 different ways to return response from asynchronous function call. You can use any of them as per your requirement. Our recommendation is to use solution #3 with Async/Await since it simplifies coding and is also the latest JavaScript standard supported by most modern web browsers and JS libraries.
Ubiq makes it easy to visualize data, and monitor them in real-time dashboards. Try Ubiq for free.
Also read:
How Slicing Works in Python
How to Ask User Input in Python Until Valid Response
How to Bind Events to Dynamic JavaScript Elements
Sreeram Sreenivasan is the Founder of Ubiq. He has helped many Fortune 500 companies in the areas of BI & software development.