Reputation: 443
I have to wait to func1 to be termined to run func2. But Since func1/2/3 contains promises it prints "termined" to early.
async function executeAsyncTask () {
const res1 = await func1(a,b,c)
const res2 = await func2(a,b,c)
const res3 = await func2(a,b,c)
return console.log(res1 , res2 , res3 )
}
executeAsyncTask ()
func1
class A{
promise_API_CALL(params){
//some code here..
}
func1(a,b,c){
//so work here...
this.promise_API_CALL(params, function( data, err ) {
if(err){console.error(err)}
console.log( data );
return data;
});
//so work here...
console.log("termined")
}
EDIT: promise_API_CALL is a function of an external library
Upvotes: 4
Views: 241
Reputation: 14464
Try wrapping the api call in a promise. Otherwise I can't see this working the way you want it to:
func1(a, b, c) {
return new Promise((resolve, reject) => {
this.promise_API_CALL(params, function(data, err) {
if (err) {
console.error(err)
reject(err);
}
console.log(data);
resolve(data);
});
//so work here...
console.log("termined")
});
}
Upvotes: 4
Reputation: 3947
In order to improve your code, the definition of executeAsyncTask
should be like this:
async function executeAsyncTask () {
try {
const res1 = await func1(a,b,c)
const res2 = await func2(a,b,c)
const res3 = await func3(a,b,c)
return [res1, res2, res3]; // Return all values from 'each await' as an array
} catch (err) {
throw 'Promise Rejected';
}
}
As you can see, it uses try
and catch
even to handle the errors. In other words, if one of the await
functions is rejected
, then catch
throws the error automatically.
// This 'func1 code' from 'Carl Edwards' is the same
func1(a, b, c) {
return new Promise((resolve, reject) => {
promise_API_CALL(params, function(data, err) {
if (err) {
console.error(err)
reject(err);
}
console.log(data);
resolve(data);
});
//so work here...
console.log("termined")
});
}
And finally you call executeAsyncTask
like this:
executeAsyncTask().then(function(result) {
console.log("result => " + result); // Result of 'res1, res2, res3'
}).catch(function(error) {
console.log("error => " + error); // Throws 'Promise Rejected'
});
And remember:
Every async
function returns a Promise
object. The await
statement operates on a Promise
, waiting until the Promise
resolve
s or reject
s.
You can use await
as many times as you like.
BONUS:
If you want all your promises (func1, func2, func3)
execute in parallel (not one after another), you can modify your executeAsyncTask
function like this:
async function executeAsyncTask () {
try {
return [ res1, res2, res3 ] = await Promise.all([
func1(a,b,c),
func2(a,b,c),
func3(a,b,c)
])
} catch (err) {
throw 'Promise Rejected';
}
}
Upvotes: 1
Reputation: 26920
This answer is very closely related to Carl Edward's answer but builds on node.js' conventions.
It's really unfortunate that promise_API_CALL()
's callback doesn't pass the error first. Otherwise you could have used util.promisify()
. One alternative is to follow node.js' Custom promisified functions. It would look something like this:
const util = require("util");
promise_API_CALL[util.promisify.custom] = function (params) {
return new Promise((resolve, reject) => {
promise_API_CALL(params, function (data, err) {
if (err) {
return reject(err);
}
resolve(data);
});
});
};
The only issue that I see is that doing this mutates the original function (which isn't yours and is a little rude bad practice). But the issue is slightly mitigated since it uses ES6's new Symbol type which should mean that you won't clobber each other.
Here is a complete example:
const util = require("util");
/**
* Use to force the API along the failure path
* @constant {Boolean}
*/
const SHOULD_FAIL = false;
/**
* Callback to deal with API responses
* @callback apiCallback
* @param {Object} data The data of the response
* @param {Error} [err] Optional error that says something went wrong
*/
/**
* Dummy API calling function
* @param {Object} kwargs api arguments
* @param {apiCallback} cb The callback that handles the response
*/
function apiCall(kwargs, cb) {
setTimeout(() => {
// Allow testing of failure path
if (SHOULD_FAIL) {
return cb(undefined, new Error("Purposefull failure"));
}
// Success path
cb({
foo: "bar"
});
}, 1000);
}
/*
* Create a function that wraps the apiCall function in a Promise
* and attach it to apiCall's util.promisify.custom Symbol
*/
apiCall[util.promisify.custom] = function (kwargs) {
return new Promise((resolve, reject) => {
apiCall(kwargs, (data, err) => {
if (err) {
return reject(err);
}
resolve(data);
});
});
};
// Create shorthand function to the promisified function
const asyncApiCall = util.promisify(apiCall);
// Sanity check to make sure that they are the same
console.log(`Are promisifies the same? ${asyncApiCall === apiCall[util.promisify.custom]}`);
// Run tester function
(async function main() {
// Do some stuff
console.log("Started");
// Use the async func
let some_data_from_api;
try {
some_data_from_api = await asyncApiCall({
fizz: "buzz"
});
} catch (err) {
console.error(err);
}
// Print the data after we have it
console.log(some_data_from_api);
//so work here...
console.log("Done")
}());
Upvotes: 0
Reputation: 10307
In order for you code to work func1 would have to be like this:
async func1(a,b,c){
const res = await promise_API_CALL(params, function( data, err ) {
if(err){console.error(err)}
console.log( data );
return data;
});
console.log("termined");
return res;
}
Then running this would work
async function executeAsyncTask () {
const res1 = await func1(a,b,c);
const res2 = await func2(a,b,c);
const res3 = await func2(a,b,c);
//yada yada yada
}
Upvotes: 0