I'm using react-select's AsyncSelect component, and try to resolve it from a callback with the following code:
loadOptions(inputValue, callback) {
this.props.asyncFunctionWithCallback(resp => {
callback(resp);
});
}
asyncFunctionWithCallback() is an async function that receives a callback
that is called when the promise is resolved:
asyncFunctionWithCallback(doneCallback) {
// Call some async code
fetch(url).then(response => {
doneCallback(response)
}
}
I'm trying to call react-select's callback() from within asyncFunctionWithCallback()'s callback, but seems like it is not being called, as asyncFunctionWithCallback() is being called repeatedly forever.
I guess I'm not passing the callback properly, but cannot figure out what am I doing wrong.
You would need to pass on the res.json value from fetch to the callback like
asyncFunctionWithCallback(doneCallback) {
// Call some async code
fetch(url)..then(res => res.json())then(response => {
doneCallback(response)
}
}
However since you already have an async code its better to use the promist approach for loadOptions
loadOptions(inputValue) {
return this.props.asyncFunctionWithCallback();
}
asyncFunctionWithCallback() {
// Call some async code
return fetch(url)..then(res => res.json());
}
Related
I am new to JavaScript and I am so confused with callbacks vs normal function calls and when to use callbacks in a real scenario.
Can someone please tell me, how both the below implementations are different from each other? or a real case scenario that makes a callback useful than a normal function call?
Using the normal function call
function getDetails(){
setTimeout(() => {
console.log("DETAILS")
}, 2000);
}
function getUser(){
setTimeout(() => {
console.log("USER");
getDetails(); // Normally calling the function
}, 3000);
}
getUser();
Using Callback
function getDetails(){
setTimeout(() => {
console.log("DETAILS")
}, 2000);
}
function getUser(callback){
setTimeout(() => {
console.log("USER");
callback(); // Calling the function
}, 3000);
}
getUser(getDetails);
There is no difference technically in the two examples you showed (assuming you won't modify getDetails before it is called). What makes it useful is that the function that calls the callback doesn't have to know the exact function to call (and could be used with different ones as needed). For instance, something like an event listener or the callback to Array.prototype.map only makes sense with the callback pattern.
But the scenario you showed ideally wouldn't use either - it should be restructured to use async/await:
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
async function getDetails (user) {
await sleep(2000)
console.log('DETAILS', user)
return 'some details'
}
async function getUser (userId) {
await sleep(3000)
console.log('USER', userId)
return 'some user'
}
async function main () {
const user = await getUser(123)
const details = await getDetails(user)
console.log('got these details:', details)
}
main().catch(e => console.error('Failed to fetch data:', e))
// If you are in an environment that supports top-level await,
// you can just use `await main()` instead
I added some more example stuff to illustrate a real use case.
I have a question about async.each behavior.
consider the code:
const examples = [1,2];
const asyncTask = (index) => {
return new Promise(resolve => {
setTimeout(() => {
console.log(`Inside setTimeout-${index}`);
resolve(true);
}, 1500)
});
}
function testingAsyncEach(callback){
async.each(examples, (example, innerCallback) => {
asyncTask(example).then(isDone => {
console.log(`isDone: ${isDone}`);
innerCallback(null);
});
}, err => {
console.log('done testingAsyncEach');
return callback()
})
}
testingAsyncEach(() => {console.log('final callback testingAsyncEach');})
a simple code using the "async" module in nodejs, using the array [1,2] and on each item in the array executing the function "asyncTask" which returns a new promise which gets resolve after a timeout of 1.5 seconds.
in this scenario the output of the program is:
Inside setTimeout-1
isDone: true
Inside setTimeout-2
isDone: true
done testingAsyncEach
final callback testingAsyncEach
but when I changed the "testingAsyncEach" function to use the "await" syntax:
function testingAsyncEach(callback){
async.each(examples, async (example, innerCallback) => {
const isDone = await asyncTask(example);
console.log(`isDone: ${isDone}`);
innerCallback(null);
}, err => {
console.log('done testingAsyncEach');
return callback()
})
}
the async.each is not waiting for the "asyncTask" to end. output:
Inside setTimeout-1
isDone: true
done testingAsyncEach
final callback testingAsyncEach
Inside setTimeout-2
isDone: true
Can you please help me understand why using the "await" instead of the "then" change the behavior? how can I still use the "await" syntax and get the proper output?
Thanks!
According to the documentation of the async module, if you pass an async function, it won't pass the innerCallback to your function. I believe that your innerCallback(null) call therefore errored, making the async.each return early. (the 2nd example is already "launched" though, so that still happens afterwards)
Check if err is set to an error, and if so, log it.
Should that be the issue, removing the innerCallback argument and call should solve it.
I have a function that I'm trying to call and basically force it to wait for a response before continuing onto the next thing.
I have two functions, both are asynchronous.
The first one looks something like this, with all parameters that begin with an '_' to be used as callbacks:
async function formatJson(input, _sendToThirdParty, _handleLogs, _setDimensions)
{
...do some work here to format the payload
if(onlineConnectionRequired)
{
_setDimensions(itemToUpdate, object);
}
else {
// Do non-online based transformations here
}
...do more work after the above
}
Basically from that, I'm trying to call this method setDimensions which looks like this:
async function setDimensions(itemToUpdate, object) {
try
{
if(itemToUpdate != null)
{
console.log("Loading dimensions");
await Promise.resolve(function() {
ns.get(`inventoryItem/${object['Item ID']}?expandSubResources=true`)
.then((res) => {
console.log("Inventory Item Loaded. Updating dimensions...");
itemToUpdate.consignments.push(
{
consignmentID: object.conID,
barcode: object.barcode,
itemID: '', // leaving as empty for now
width : res.data.custitem_width,
length : res.data.custitem_length,
height : res.data.custitem_height,
weight : res.data.custitem_weight,
fragile: object.fragile === 'T' ? 1 : 0,
description: object.description
}
);
console.log("Dimensions Finalised");
})
});
}
}
catch(err)
{
console.log(err);
const message = `Error attempting to set the dimensions for ${object['Item ID']}`;
console.log(message);
throw new Error(message);
}
}
The problems I'm coming across are:
The code from the first method continues on before waiting for the promise to resolve, but I need it to wait so I can fully finish building up the payload before it continues on doing the next bits
If I try and include the await keyword before my call to _setDimensions(...) in the first method, I get an error "SyntaxError: await is only valid in async function", but I would've thought that it was an async function?
If anyone could help, that would be incredibly appreciated! Thank you!!
The correct design of your functions are below:
formatJson(input, (err, value) => {
if(err) {
// Error handler goes here
//console.log(err);
throw err;
} else {
// Implementation for working with returned value
console.log(value);
}
});
function formatJson(input, callback)
{
//...do some work here to format the payload
if(onlineConnectionRequired)
{
setDimensions(itemToUpdate, object)
.then((updatedItem) => {
// Implement anything here to work with your
// result coming from setDimensions() function
//console.log(updatedItem);
// Callback with null error and updatedItem as value
callback(null, updatedItem);
})
.catch((err) => {
// Callback with err object and null value
callback(err, null);
});
}
else {
// Do non-online based transformations here
}
//...do more work after the above
}
function setDimensions(itemToUpdate, object) {
try
{
if(inventoryItemID != null)
{
console.log("Loading dimensions");
return new Promise(function(resolve, reject) {
ns.get(`inventoryItem/${object['Item ID']}?expandSubResources=true`)
.then((res) => {
console.log("Inventory Item Loaded. Updating dimensions...");
itemToUpdate.consignments.push(
{
consignmentID: object.conID,
barcode: object.barcode,
itemID: '', // leaving as empty for now
width : res.data.custitem_width,
length : res.data.custitem_length,
height : res.data.custitem_height,
weight : res.data.custitem_weight,
fragile: object.fragile === 'T' ? 1 : 0,
description: object.description
}
);
console.log("Dimensions Finalised");
resolve(itemToUpdate);
})
.catch((err) => reject(err));
});
}
}
catch(err)
{
console.log(err);
const message = `Error attempting to set the dimensions for ${object['Item ID']}`;
console.log(message);
throw new Error(message);
}
}
Mistakes in your code:
Your formatJson function had async keyword but your formatJson function had callback functions named _sendToThirdParty, _handleLogs, _setDimensions. There are 3 types of implementation to create asynchronous codes. You can use callbacks, Promises or async/await. But Promises and async/await are the same except their uses cases and syntaxses. When you define a function as async fn() {...} it basically return a new Promise, so it is equal saying fn() { return new Promise(); }. Functions with callbacks have a shape like function(params, callback) { callback(cbParams); } you can use call callback function in a several branches in your function. But you only have single callback function, your code had 3 callback functions. Also note that functions with callback don't have async keyword. This is not valid because as I mentioned earlier, an async function will return a Promise. So you should not (but you can) define a function as async function(params, callback) like you did in your first method. This is definition is not wrong and it can work but it's not valid.
Your second method was an async function which was returning nothing. So I have changed it to normal function with returning a Promise.
Is the formatJson method beeing called inside an async method? It need to be, and before _setDimensions you need to add a await keyword.
And, as Daniel said, use the promise constructor.
This question already has answers here:
async/await implicitly returns promise?
(5 answers)
Closed 1 year ago.
When I console.log(data), I log the information I need, but if return the value of data in getWeather(), it just returns a pending promise. I have tried many things, but none have worked so far. I'll leave my broken code below.
const axios = require('axios');
const getWeather = async () => {
try {
let response = await axios.get(
'http://api.openweathermap.org/data/2.5/forecast?id=524901&appid={apiKey}'
);
let data = response.data;
return data;
} catch (e) {
console.log(e);
}
};
async function returnAsync() {
const x = await getWeather();
return x;
}
console.log(getWeather()); // returns a pending promise
console.log('check ', returnAsync()); // also returns a pending promise
async functions must return a promise. (they implicitly return Promise<void> instead of void!)
Async functions always return a promise. If the return value of an async function is not explicitly a promise, it will be implicitly wrapped in a promise.
For example, the following:
async function foo() {
return 1
}
...is equivalent to:
function foo() {
return Promise.resolve(1)
}
Source
This could be to do with the fact that you're trying to call an async function inside of a synchronous function. It's quite a common mistake to make, so don't fret. Typically if you think about the structure, the console logs could technically be run before the async function has completed. That's why we have "callback functions" which basically just run as soon as the async returns a value.
Axios has a really neat way to use these callbacks which is just using the .then() function.
So try this out and see if it works:
const axios = require('axios');
const getWeather = async () => {
axios.get('http://api.openweathermap.org/data/2.5/forecast?id=524901&appid={apiKey}')
.then(json => console.log(json))
.catch(error => console.log(error))
};
getWeather();
Because you're trying to call the get request inside of an async function, you cannot then grab the data in a synchronous function.
//const getWeather = async () => {...
An async function's return value will be a Promise which will be resolved with the value returned by the async function, or rejected with an exception thrown from, or uncaught within, the async function.
check more at
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
I have my JS set up as follows.
App1.js
function x(){
thirdPartyLibrary.performAsyncTask((resultObject, errorObject) => {
// This is a callback function, invoked when performAsyncTask is done.
// I can handle resultObject and errorObject here.
});
}
Let's say I have other files as part of this app. Each of them calls x(), and would invoke their own version of a handleSuccess() or handleError() function depending on the results of the call to x().
How can I structure the call to x() such that I can achieve this? It's almost like I want to "listen" to the results of performAsyncTask() from App1.js, but I'm not sure how to do that.
If you need to stay with callbacks (due to very old JS clients or whatever), you can provide the callback as parameter to x:
function x(myCallback) {
thirdPartyLibrary.performAsyncTask(myCallback);
}
// other file:
x((resultObject, errorObject) => {
// handle just like before
});
You could even change it to two callbacks, depending on the result. Only one of your callbacks will be called in the end:
function x(successCallback, errorCallback) {
thirdPartyLibrary.performAsyncTask((resultObject, errorObject) => {
if (errorObject) return errorCallback(errorObject);
else return successCallback(resultObject);
});
}
// other file:
x(
function handleSuccess(resultObject) {
// handle success
},
function handleError(errorObject) {
// handle error
}
);
Have x return a Promise that resolves with resultObject if there's no error, or rejects with errorObject if there is an error. Then, callers of x can chain .then onto the Promise to handle successes, and chain .catches to handle failures:
function x(){
return new Promise((resolve, reject) => {
thirdPartyLibrary.performAsyncTask((resultObject, errorObject) => {
if (errorObject) reject(errorObject);
else resolve(resultObject);
});
});
}
x()
.then(result => {
// handle successful result
})
.catch(err => {
// handle error
});