snippetjavascriptCritical
How do I return the response from an asynchronous call?
Viewed 0 times
howfromreturntheasynchronouscallresponse
Problem
How do I return the response/result from a function
I am trying to return the value from the callback, as well as assigning the result to a local variable inside the function and returning that one, but none of those ways actually return the response — they all return
Example of an asynchronous function that accepts a callback (using jQuery's
Example using Node.js:
Example using the
foo that makes an asynchronous request?I am trying to return the value from the callback, as well as assigning the result to a local variable inside the function and returning that one, but none of those ways actually return the response — they all return
undefined or whatever the initial value of the variable result is.Example of an asynchronous function that accepts a callback (using jQuery's
ajax function):function foo() {
var result;
$.ajax({
url: '...',
success: function(response) {
result = response;
// return response; // <- I tried that one as well
}
});
return result; // It always returns `undefined`
}Example using Node.js:
function foo() {
var result;
fs.readFile("path/to/file", function(err, data) {
result = data;
// return data; // <- I tried that one as well
});
return result; // It always returns `undefined`
}Example using the
then block of a promise:function foo() {
var result;
fetch(url).then(function(response) {
result = response;
// return response; // <- I tried that one as well
});
return result; // It always returns `undefined`
}Solution
→ For a more general explanation of asynchronous behaviour with different examples, see Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
→ If you already understand the problem, skip to the possible solutions below.
The problem
The A in Ajax stands for asynchronous. That means sending the request (or rather receiving the response) is taken out of the normal execution flow. In your example,
Here is an analogy which hopefully makes the difference between synchronous and asynchronous flow clearer:
Synchronous
Imagine you make a phone call to a friend and ask him to look something up for you. Although it might take a while, you wait on the phone and stare into space, until your friend gives you the answer that you needed.
The same is happening when you make a function call containing "normal" code:
Even though
Asynchronous
You call your friend again for the same reason. But this time you tell him that you are in a hurry and he should call you back on your mobile phone. You hang up, leave the house, and do whatever you planned to do. Once your friend calls you back, you are dealing with the information he gave to you.
That's exactly what's happening when you do an Ajax request.
Instead of waiting for the response, the execution continues immediately and the statement after the Ajax call is executed. To get the response eventually, you provide a function to be called once the response was received, a callback (notice something? call back ?). Any statement coming after that call is executed before the callback is called.
Solution(s)
Embrace the asynchronous nature of JavaScript! While certain asynchronous operations provide synchronous counterparts (so does "Ajax"), it's generally discouraged to use them, especially in a browser context.
Why is it bad do you ask?
JavaScript runs in the UI thread of the browser and any long-running process will lock the UI, making it unresponsive. Additionally, there is an upper limit on the execution time for JavaScript and the browser will ask the user whether to continue the execution or not.
All of this results in a really bad user experience. The user won't be able to tell whether everything is working fine or not. Furthermore, the effect will be worse for users with a slow connection.
In the following we will look at three different solutions that are all building on top of each other:
All three are available in current browsers, and node 7+.
ES2017+: Promises with
The ECMAScript version released in 2017 introduced syntax-level support for asynchronous functions. With the help of
Important: You can only use
You can read more about
Here is an example that elaborates the delay function
``
setTimeout(function() {
resolve(42); // After 3 seconds, resolve the promise with value 42
}, 3000);
});
}
async function getAllBooks() {
try {
// GET a list of book IDs of the current user
var bookIDs = await superagent.get('/user/books');
// wait for 3 seconds (just for the sake of this example)
await delay();
// GET information about each book
return superagent.get('/books/ids='+JSO
→ If you already understand the problem, skip to the possible solutions below.
The problem
The A in Ajax stands for asynchronous. That means sending the request (or rather receiving the response) is taken out of the normal execution flow. In your example,
$.ajax returns immediately and the next statement, return result;, is executed before the function you passed as success callback was even called.Here is an analogy which hopefully makes the difference between synchronous and asynchronous flow clearer:
Synchronous
Imagine you make a phone call to a friend and ask him to look something up for you. Although it might take a while, you wait on the phone and stare into space, until your friend gives you the answer that you needed.
The same is happening when you make a function call containing "normal" code:
function findItem() {
var item;
while(item_not_found) {
// search
}
return item;
}
var item = findItem();
// Do something with item
doSomethingElse();Even though
findItem might take a long time to execute, any code coming after var item = findItem(); has to wait until the function returns the result.Asynchronous
You call your friend again for the same reason. But this time you tell him that you are in a hurry and he should call you back on your mobile phone. You hang up, leave the house, and do whatever you planned to do. Once your friend calls you back, you are dealing with the information he gave to you.
That's exactly what's happening when you do an Ajax request.
findItem(function(item) {
// Do something with the item
});
doSomethingElse();Instead of waiting for the response, the execution continues immediately and the statement after the Ajax call is executed. To get the response eventually, you provide a function to be called once the response was received, a callback (notice something? call back ?). Any statement coming after that call is executed before the callback is called.
Solution(s)
Embrace the asynchronous nature of JavaScript! While certain asynchronous operations provide synchronous counterparts (so does "Ajax"), it's generally discouraged to use them, especially in a browser context.
Why is it bad do you ask?
JavaScript runs in the UI thread of the browser and any long-running process will lock the UI, making it unresponsive. Additionally, there is an upper limit on the execution time for JavaScript and the browser will ask the user whether to continue the execution or not.
All of this results in a really bad user experience. The user won't be able to tell whether everything is working fine or not. Furthermore, the effect will be worse for users with a slow connection.
In the following we will look at three different solutions that are all building on top of each other:
- Promises with
async/await(ES2017+, available in older browsers if you use a transpiler or regenerator)
- Callbacks (popular in node)
- Promises with
then()(ES2015+, available in older browsers if you use one of the many promise libraries)
All three are available in current browsers, and node 7+.
ES2017+: Promises with
async/awaitThe ECMAScript version released in 2017 introduced syntax-level support for asynchronous functions. With the help of
async and await, you can write asynchronous in a "synchronous style". The code is still asynchronous, but it's easier to read/understand.async/await builds on top of promises: an async function always returns a promise. await "unwraps" a promise and either result in the value the promise was resolved with or throws an error if the promise was rejected.Important: You can only use
await inside an async function or in a JavaScript module. Top-level await is not supported outside of modules, so you might have to make an async IIFE (Immediately Invoked Function Expression) to start an async context if not using a module.You can read more about
async and await on MDN.Here is an example that elaborates the delay function
findItem() above:``
// Using 'superagent' which will return a promise.
var superagent = require('superagent')
// This is isn't declared as async because it already returns a promise
function delay() {
// delay returns a promise
return new Promise(function(resolve, reject) {
// Only delay` is able to resolve or reject the promisesetTimeout(function() {
resolve(42); // After 3 seconds, resolve the promise with value 42
}, 3000);
});
}
async function getAllBooks() {
try {
// GET a list of book IDs of the current user
var bookIDs = await superagent.get('/user/books');
// wait for 3 seconds (just for the sake of this example)
await delay();
// GET information about each book
return superagent.get('/books/ids='+JSO
Code Snippets
function findItem() {
var item;
while(item_not_found) {
// search
}
return item;
}
var item = findItem();
// Do something with item
doSomethingElse();findItem(function(item) {
// Do something with the item
});
doSomethingElse();// Using 'superagent' which will return a promise.
var superagent = require('superagent')
// This is isn't declared as `async` because it already returns a promise
function delay() {
// `delay` returns a promise
return new Promise(function(resolve, reject) {
// Only `delay` is able to resolve or reject the promise
setTimeout(function() {
resolve(42); // After 3 seconds, resolve the promise with value 42
}, 3000);
});
}
async function getAllBooks() {
try {
// GET a list of book IDs of the current user
var bookIDs = await superagent.get('/user/books');
// wait for 3 seconds (just for the sake of this example)
await delay();
// GET information about each book
return superagent.get('/books/ids='+JSON.stringify(bookIDs));
} catch(error) {
// If any of the awaited promises was rejected, this catch block
// would catch the rejection reason
return null;
}
}
// Start an IIFE to use `await` at the top level
(async function(){
let books = await getAllBooks();
console.log(books);
})();var result = foo();
// Code that depends on 'result'foo(function(result) {
// Code that depends on 'result'
});Context
Stack Overflow Q#14220321, score: 6659
Revisions (0)
No revisions yet.