Async function called with call or apply never resolved - javascript

Functions that are called with call or apply using await never resolve, please check the following code snippet
const obj = {
resolveAfter2Seconds: function() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
}
async function asyncCall() {
console.log('calling');
var result = await obj.resolveAfter2Seconds();
console.log(result);//resolved
var result2 = await obj.call("resolveAfter2Seconds");
console.log(result2);//never alled
}
asyncCall();

Just expanding #CertainPermances comment - call is a function method used to assign an option to this inside the function, you can't use it on an object
(function() {
const obj = {
resolveAfter2Seconds : function() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
}
async function asyncCall() {
console.log('calling');
var result = await obj.resolveAfter2Seconds();
console.log(result);//resolved
// var result2 = await obj.call("resolveAfter2Seconds"); caused an eror
var result2 = await obj.resolveAfter2Seconds();
// or
var result2 = await obj.resolveAfter2Seconds.call( obj /* perhaps */); // which makes no difference at all because this = obj anyway
console.log(result2);
}
asyncCall();
})();

I was asking the question in wrong way, I ended up using the correct syntax as follows
const obj = {
resolveAfter2Seconds: function() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
}
async function asyncCall() {
console.log('calling');
var result = await obj.resolveAfter2Seconds();
console.log(result);//resolved
var result2 = await obj["resolveAfter2Seconds"].call();
console.log(result2);//never alled
}
asyncCall();

Related

How to write await() for multiple promises in JavaScript?

I m trying to write await for multiple promises, instead of nested functions.
Please take a look at the below code i tried, as it will explain better than me.
var main = async () => {
// const main_ = await Promise.all(fun1,fun2,fun3);
// Fun 3
const fun3 = () =>
new Promise((resolve) => async () => {
// console.log(1);
return resolve(await fun2(1));
});
// Fun 2
const fun2 = (value) =>
new Promise((resolve) => async (value) => {
value = value + 1;
// console.log(value);
return resolve(await fun1(value));
});
// Fun 1
const fun1 = () =>
new Promise((resolve) => (value) => {
value = value + 1;
// console.log(value);
return resolve(value);
});
fun3();
};
main();
I tried console logging to debut but I m getting nothing in the console.
Any help is greatly appreciated.
the syntax is wrong, its not new Promise((resolve) => async () => {}) with 2 arrow, but new Promise((resolve) => {}) also you can call promise function without await
var main = async () => {
// const main_ = await Promise.all(fun1,fun2,fun3);
// Fun 3
const fun3 = () => new Promise(resolve => {
//console.log(1);
return resolve(fun2(1));
});
// Fun 2
const fun2 = (value) => new Promise(resolve => {
value = value + 1;
//console.log(value);
return resolve(fun1(value));
});
// Fun 1
const fun1 = (value) => new Promise(async (resolve) => {
value = value + 1;
console.log('sleep 3 seconds');
await new Promise(r => setTimeout(r, 3000));
console.log(value);
return resolve(value);
});
fun3();
};
main();
If you want to call await inside a Promise callback, you can do this:
const p = new Promise((resolve) => {
(async () => {
const res = await anotherPromise();
resolve(res);
})();
});
So with this in mind, you can rewrite your functions like this:
var main = async () => {
// const main_ = await Promise.all(fun1,fun2,fun3);
// Fun 3
const fun3 = () =>
new Promise((resolve) => {
(async () => {
resolve(await fun2(1));
})();
});
// Fun 2
const fun2 = (value) =>
new Promise((resolve) => {
value = value + 1;
(async () => {
resolve(await fun1(value));
})();
});
// Fun 1
const fun1 = (value) =>
new Promise((resolve) => {
value = value + 1;
(async () => {
resolve(value);
})();
});
return await fun3();
};
// ans: 3
console.log(await main());
If you want to do it in pure async/await, you may do this:
const main = async () => {
const fun1 = async (value) => value + 1;
const fun2 = async (value) => await fun1(value + 1);
const fun3 = async () => await fun2(1);
return await fun3();
}
// output: 3
console.log(await main());
I hope this example works for you.
console.clear();
function wait(ms, data) {
return new Promise( resolve => setTimeout(resolve.bind(this, data), ms) );
}
/**
* These will be run in series, because we call
* a function and immediately wait for each result,
* so this will finish in 1s.
*/
async function series() {
return {
result1: await wait(500, 'seriesTask1'),
result2: await wait(500, 'seriesTask2'),
}
}
/**
* While here we call the functions first,
* then wait for the result later, so
* this will finish in 500ms.
*/
async function parallel() {
const task1 = wait(500, 'parallelTask1');
const task2 = wait(500, 'parallelTask2');
return {
result1: await task1,
result2: await task2,
}
}
async function taskRunner(fn, label) {
const startTime = performance.now();
console.log(`Task ${label} starting...`);
let result = await fn();
console.log(`Task ${label} finished in ${ Number.parseInt(performance.now() - startTime) } miliseconds with,`, result);
}
void taskRunner(series, 'series');
void taskRunner(parallel, 'parallel');
fun3() is an async function so you have to put await before the call.
var main = async () => {
// Fun 3
const fun3 = () => new Promise(resolve => {
//console.log(1);
return resolve(fun2(1));
});
// Fun 2
const fun2 = (value) => new Promise(resolve => {
value = value + 1;
//console.log(value);
return resolve(fun1(value));
});
// Fun 1
const fun1 = (value) => new Promise(async (resolve) => {
value = value + 1;
console.log('sleep 3 seconds');
await new Promise(r => setTimeout(r, 3000));
console.log(value);
return resolve(value);
});
await fun3();
};
main();

Function calls from data.map are not executed synchronously

I am trying to call same function from map. Depending upon number of entries function will be called.
Here is my code
getDetails = (inputData) => {
const data = {
accountName: "test",
};
let url = `/rest/jarvis/reports/v1/getData`;
let thisdata = this;
post(url, data)
.then((response) => {
if (
response.data &&
response.data.sb &&
response.data.sb.length > 0
) {
this.props.bs.betDetails = {
data: [...response.data.sportsbookBets],
exportAccesses: response.data.exportAccesses,
};
this.props.bs.betDetails.data.map((value, index) => {
console.log("Index Value --->", index);
this.getEventDetails(value, index);
}),
this.updateReducer({
...this.props.bs,
});
}
}
}
getEventDetails = async (value, index) => {
let _this = this;
let myPromise = new Promise(function (myResolve, myReject) {
console.log("Index Value at the entry--->", index);
const data = {
accountName: "test",
};
let url = `/rest/jarvis/reports/v1/getBetEventData`;
post(url, data).then((response) => {
if (response.data) {
console.log("Index Value inside--->", index);
_this.eventIdIndexMap.set(
list.eventId != null
? list.eventId
: _this.props.bs.betEventRequest.EventId,
index
);
_this.props.bs.testEventDetails[
_this.eventIdIndexMap.get(
list.eventId != null
? list.eventId
: _this.props.bs.betEventRequest.EventId
)
] = _this.props.bs.betEventResponse;
}}}
await myPromise;
}
Here problem I am facing is inside post call of 'getEventDetails' index values are not getting in sequence.
I have used promise await and async but it is not working.
Can someone please tell me how to get it properly ?
map calls its callback function without await. You can use asynchronous functions in the callback function but they won't be executed in order.
But you can create your own map with await:
async function map(array, cb) {
const result = [];
for (const element of array) {
result.push(await cb(element));
}
return result;
}
async function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
(async () => {
console.log(await map([3, 2, 1], async el => { await sleep(el * 100); return 2 * el; }));
})();
or create your own Array.prototype.syncMap:
Array.prototype.syncMap = async function(cb) {
const result = [];
for (const element of this) {
result.push(await cb(element));
}
return result;
}
async function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
(async () => {
console.log(await [3, 2, 1].syncMap(async el => { await sleep(el * 100); return 2 * el; }));
})();
It looks like you don't even need a result. You can write your own Array.prototype.syncForEach:
Array.prototype.syncForEach = async function(cb) {
for (const element of this) {
await cb(element);
}
}
async function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
[3, 2, 1].syncForEach(async el => { await sleep(el * 100); console.log(2 * el); });
[30, 20, 10].forEach(async el => { await sleep(el * 10); console.log(2 * el); });
As you can see in the output the functions in syncForEach are executed in order and the functions in forEach are executed out of order.

How to call an asynchronous JavaScript function?

Can anyone please help me with the following, I am new to Async\Await in Javascript:
I have a trivial class:
function Thing()
{
}
Thing.prototype.ShowResult = function ()
{
var result = this.GetAsync();
alert(result);
}
Thing.prototype.GetAsync = async function ()
{
var result = await this.AsyncFunc();
return result;
}
Thing.prototype.AsyncFunc = async function ()
{
return new Promise(resolve => {
setTimeout(() => {
resolve(6);
}, 2000);
});
}
I call it like this:
var thing = new Thing();
thing.ShowResult();
I expected a delay of 2 seconds before seeing the result of 6.
Instead I immediately see:
[object Promise]
How can I correctly await the result? Thanks for any help.
You have to make the parent function consuming the async function async as well.
function Thing() {}
Thing.prototype.ShowResult = async function() { // add async
var result = await this.GetAsync(); // await the response
alert(result);
}
Thing.prototype.GetAsync = async function() {
var result = await this.AsyncFunc();
return result;
}
Thing.prototype.AsyncFunc = async function() {
return new Promise(resolve => {
setTimeout(() => {
resolve(6);
}, 2000);
});
}
Then you can call ShowResult
var thing = new Thing();
await thing.ShowResult();
But, if you're calling thing.ShowResult outside of an async function you'll have to use the Promise syntax since you can't await something that isn't in an async function. There's no concept of a "top level await" in JS. Yet.
var thing = new Thing();
thing.ShowResult().then( result => console.log(result) );
In JavaScript, async functions always return a Promise (this is why you see [object Promise]), which can be resolved either by calling its then method or by using the await keyword. For now, await can only be used inside async functions.
To apply this to your problem, you can do one of the following:
#1
Thing.prototype.ShowResult = function ()
{
this.GetAsync().then(alert);
}
thing.ShowResult();
#2
In this approach, ShowResult is also an async function. So what I wrote above also applies to it.
Thing.prototype.ShowResult = async function ()
{
var result = await this.GetAsync();
}
await thing.ShowResult();
Though AsyncFunc and GetAsync are async functions. ShowResult function is not. It is necessary for the parent function to be async as well. The below code returns 6.
function Thing()
{
}
Thing.prototype.ShowResult = async function ()
{
var result = await this.GetAsync();
alert(result);
}
Thing.prototype.GetAsync = async function ()
{
var result = await this.AsyncFunc();
return result;
}
Thing.prototype.AsyncFunc = async function ()
{
return new Promise(resolve => {
setTimeout(() => {
resolve(6);
}, 2000);
});
}
var thing = new Thing();
thing.ShowResult();
Your function GetAsync() return a promise to consume the promise you have to either use await or .then read more about async/await
function Thing() {}
Thing.prototype.ShowResult = async function() {
var result = await this.GetAsync();
alert(result);
}
Thing.prototype.GetAsync = async function() {
var result = await this.AsyncFunc();
return result;
}
Thing.prototype.AsyncFunc = async function() {
return new Promise(resolve => {
setTimeout(() => {
resolve(6);
}, 2000);
});
}
var thing = new Thing();
thing.ShowResult();
using .then
function Thing() {}
Thing.prototype.ShowResult = async function() {
var result = this.GetAsync().then((result)=>alert(result));
}
Thing.prototype.GetAsync = async function() {
var result = await this.AsyncFunc();
return result;
}
Thing.prototype.AsyncFunc = async function() {
return new Promise(resolve => {
setTimeout(() => {
resolve(6);
}, 2000);
});
}
var thing = new Thing();
thing.ShowResult();

How can I be sure that it first starts with the "Startpoint" function call and waits until this one is resolved to start the next function call?

Within a map function, I want to call an asynchronous function if the name is "Startpoint" and the same function if the name is "Question". These functions call an API (from dialogflow). I have the problem that the second function call overtakes the first one.
How can I be sure that it first starts with the "Startpoint" function call and waits until this one is resolved to start the next function?
Here is the code:
const editorJSON = {1: "Startpoint", 2: "Answer", 3: "Question"};
Object.keys(editorJSON).map((key, index) => {
if (editorJSON[key].name === "Startpoint") {
saveNodeasIntentinDialogflow(someArgument);
if (editorJSON[key].name === "Question") {
saveNodeasIntentinDialogflow(someArgument);
And here is the function saveNodeasIntentinDialogflow (simplified):
const saveNodeAsIntentinDialogflow = async (someParameter) => {
try {
const res = await axios.post(
`https://dialogflow.googleapis.com/v2/projects/agent/intents:batchUpdate`)}
One working solution is to split them up into two different maps
const editorJSON = {
1: "Startpoint",
2: "Answer",
3: "Question"
};
//console logged at end to show output order
const order = [];
//longer async
async function mockLonger(param) {
return await new Promise(function(resolve, reject) {
setTimeout(() => resolve(order.push(param)), 2000);
})
}
//shorter async
async function mockShorter(param) {
return await new Promise(function(resolve, reject) {
setTimeout(() => resolve(order.push(param)), 1000);
})
}
//async map
async function mapArray(array) {
console.log("processing...");
const resultsA = array.map(async(key, index) => {
if (editorJSON[key] === "Startpoint") await mockLonger("longer");
})
//process longer call first
await Promise.all(resultsA)
const resultsB = array.map(async(key, index) => {
if (editorJSON[key] === "Question") await mockShorter("shorter");
})
//then shorter call
await Promise.all(resultsB)
console.log("Output Order:", order)
}
mapArray(Object.keys(editorJSON));
Why does it have to be within a map function? Just iterate the array and await.
const editorJSON = {1: "Startpoint", 2: "Answer", 3: "Question"};
(async () => {
for (const value of Object.values(editorJSON)) {
await saveNodeasIntentinDialogflow(value);
}
})();
async function saveNodeasIntentinDialogflow(name) {
await new Promise(r => setTimeout(r, 3000 * Math.random()));
console.log(`${name} is done`);
}

How to merge asynchronous function's callback result

Here is the code to get some information about server.
cpu.usage()
.then(info => {
console.log(info);
});
cpu.free()
.then(info => {
console.log(info)
});
mem.info()
.then(info => {
console.log(info)
});
I want to get every result in a function.
get_resource () {
...
console.log(cpu_usage, cpu_free, mem_info);
};
How can I design it?
Thank you.
You can try to use async/await to do that:
var get_resource = async function () {
var cpu_usage = await cpu.usage();
var cpu_free = await cpu.free();
var mem_info = await mem.info();
console.log(cpu_usage, cpu_free, mem_info);
};
Or
Promise.all([cpu.usage(), cpu.free(), mem.info()]).then(function (info) {
console.log('cpu_usage:', info[0]);
console.log('cpu_free:', info[1]);
console.log('mem_info:', info[2]);
})
You can use Promise.all() as following:
let cpuUsage = cpu.usage()
let cpuFree = cpu.free()
let memInfo = mem.info()
Promise.all([cpuUsage, cpuFree, memInfo]).then((values) => {
console.log(values);
});
If you can use ES6, then you can use array destructuring while getting results:
Promise.all([cpuUsage, cpuFree, memInfo]).then(([cpuUsageResult, cpuFreeResult, memInfoResult]) => {
console.log(cpuUsageResult);
console.log(cpuFreeResult);
console.log(memInfoResult);
});
Callback Hell
This is the old scenario where you would have to call things inside one another
cpu.usage()
.then(cpu_usage => {
cpu.free()
.then(cpu_free => {
mem.info()
.then(mem_info => {
console.log(cpu_usage, cpu_free, mem_info);
});
});
});
Async Await
in this scenario you make a function that is asynchronous.
async function get_resource () {
const cpu_usage = await cpu.usage();
const cpu_free = await cpu.free();
const mem_info = await mem.info();
console.log(cpu_usage, cpu_free, mem_info);
};
The value assigned to each const in the async function is the same value that you get as an argument in the callback of the then.

Categories