const fun = (x) => {
console.log(`Meth... ${x}`);
setTimeout(() => {
onReceive(`Fun Received: ${x}`);
}, 100);
return x;
}
const publish = () => {
return new Promise(resolve => {
window.onReceive = (token) => {
resolve(token);
}
});
}
const Inst = () => {
const getAs = async(x) => {
console.log(`Getting As ----- ${x}`);
const res = await publish(fun(x));
console.log(`Res is '${res}' ---- ${x}`);
}
return {
getAs,
}
}
const inst = Object.freeze(Inst());
const a = async() => {
await inst.getAs(1);
await inst.getAs(2);
await inst.getAs(3);
await inst.getAs(4);
await inst.getAs(5);
};
a();
const b = async() => {
await inst.getAs(4);
await inst.getAs(5);
await inst.getAs(6);
await inst.getAs(7);
};
b();
// Comment or remove `b()` to see the different result in Console
I got confused why the function only called the last async await (b() from the example). Why inside of a() seems like didn't get called at all??
If I comment / remove b(), all inside of a() will get call.
Need helps / explanation to resolve such issue 🙏.
Related
The Problem is with the uplines.push.
I always get an empty uplines array so the last part of the code doesn't run. The promises resolve later and I get the correct data. May I know how to go about doing it the correct way?
const getAllUplines = async () => {
uplines = [];
const findUser = async (userFid) => {
const userDoc = await firestore.collection("users").doc(userFid).get();
if (userDoc.exists) {
const user = { ...userDoc.data(), id: userDoc.id };
console.log(user);
uplines.push(user);
if (user.immediateUplineFid) {
findUser(user.immediateUplineFid); //self looping
}
} else {
console.log("No User Found");
return null;
}
};
sale.rens.forEach(async (ren) => {
findUser(ren.userFid);
});
console.log(uplines);
return uplines;
};
let uplines = await getAllUplines();
console.log(uplines);
uplines = uplines.filter(
(v, i) => uplines.findIndex((index) => index === v) === i
); //remove duplicates
uplines.forEach((user) => {
if (user.chatId) {
sendTelegramMessage(user.chatId, saleToDisplay, currentUser.displayName);
console.log("Telegram Message Sent to " + user.displayName);
} else {
console.log(user.displayName + " has no chatId");
}
});
There are a few things that you have missed out while implementing the async call, which are explained in the inline comments in the code snippet.
A short explanation for what happened in your code is that in the line sale.rens.forEach you are passing an async function in the argument, which does not make any difference to the function forEach, it will execute it without waiting for it to complete.
Therefore in my answer I am using Promise.all to wait for all the async function calls to complete before returning the result.
// This is wrapped in an immediately executed async function because await in root is not supported here
(async () => {
const mockGetData = () => new Promise(resolve => setTimeout(resolve, 1000));
const sale = {
rens: [
{ userFid: 1 },
{ userFid: 2 },
{ userFid: 3 }
]
};
const getAllUplines = async () => {
const uplines = [];
const findUser = async (userFid) => {
// Simulating an async function call
const userDoc = await mockGetData();
console.log("User data received");
uplines.push(`User ${userFid}`);
};
const promises = [];
sale.rens.forEach(ren => { // This function in foreach does not have to be declared as async
// The function findUser is an async function, which returns a promise, so we have to keep track of all the promises returned to be used later
promises.push(findUser(ren.userFid));
});
await Promise.all(promises);
return uplines;
};
let uplines = await getAllUplines();
console.log(uplines);
})();
In order to get the results of getAllUplines() properly, you need to add await to all async functions called in getAllUplines().
const getAllUplines = async () => {
uplines = [];
const findUser = async (userFid) => {
const userDoc = await firestore.collection("users").doc(userFid).get();
if (userDoc.exists) {
const user = { ...userDoc.data(), id: userDoc.id };
console.log(user);
uplines.push(user);
if (user.immediateUplineFid) {
await findUser(user.immediateUplineFid); //self looping
}
} else {
console.log("No User Found");
return null;
}
};
sale.rens.forEach(async (ren) => {
await findUser(ren.userFid);
});
console.log(uplines);
return uplines;
};
I was wondering if it's possible to create a nameless function with the quick functional notation on javascript. What I mean by changing this:
var lobby = ((io) => {
...
}
return {
getWhiteBoardId: (name2, time2, role2, pass2, need_id) => {
let promise = new Promise((res, rej) => {
setTimeout(() => res("Now it's done!"), 1000)
});
// wait until the promise returns us a value
let result = await promise;
}
})(io);
I then want to later be able to call this function:
whiteboardId = lobby.getWhiteBoardId(req.body.name, req.body.time, req.body.role, req.body.pass, need_id);
to have something at the beginning such as this:
var lobby = (async (io) => {
so that I can call my Promise and await
// defining io, to execute the code, you not need to write the next line
const io = {};
const lobby = ((io) => {
// some pre-existing code
return {
// you are using await in this method so add async to the method signature
getWhiteBoardId: async (...args) => {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve(args), 1000)
});
// wait until the promise returns us a value
let result = await promise;
// ... some other code/logic as needed
// i have assumed you need to return the result
return result;
}
}
})(io);
// TEST: calling getWhiteBoardID method
lobby.getWhiteBoardId("Hi", "There").then(console.log);
// or
(async () => {
const res = await lobby.getWhiteBoardId("Hello World")
console.log(res);
})();
console.log("First!");
The following behavior of Javascript is a complete mystery to me. The following code snippet does not work:
let someFunctionOne = async () => (new Promise(resolve => setTimeout(resolve(1), 1000)))
let someFunctionTwo = async () => (new Promise(resolve => setTimeout(resolve(2), 1000)))
let someFunctionThree = async () => (new Promise(resolve => setTimeout(resolve(3), 1000)))
let myFunction = async () => {
let resultOne
if (true) {
let resultTwo, resultThree // <-- doesn't work
if (false) {
throw new Error('Something went wrong')
}
const promiseOne = someFunctionOne()
const promiseTwo = someFunctionTwo()
const promiseThree = someFunctionThree()
[resultOne, resultTwo, resultThree] = await Promise.all([
promiseOne,
promiseTwo,
promiseThree]
)
resultOne = {resultOne, resultTwo, resultThree}
}
return resultOne
}
let result = await myFunction()
console.log(result)
This throws the following error:
ReferenceError: Cannot access 'promiseThree' before initialization
However, when the initialization of the two variables is put right above the Promise.all() call it does work:
let someFunctionOne = async () => (new Promise(resolve => setTimeout(resolve(1), 1000)))
let someFunctionTwo = async () => (new Promise(resolve => setTimeout(resolve(2), 1000)))
let someFunctionThree = async () => (new Promise(resolve => setTimeout(resolve(3), 1000)))
let myFunction = async () => {
let resultOne
if (true) {
if (false) {
throw new Error('Something went wrong')
}
const promiseOne = someFunctionOne()
const promiseTwo = someFunctionTwo()
const promiseThree = someFunctionThree()
let resultTwo, resultThree // <-- does work
[resultOne, resultTwo, resultThree] = await Promise.all([
promiseOne,
promiseTwo,
promiseThree]
)
resultOne = {resultOne, resultTwo, resultThree}
}
return resultOne
}
let result = await myFunction()
console.log(result)
Why on earth is the second code snippet working and the first one isn't? For both, the variable initialization of resultTwo and resultThree happen before they are used...
Thanks
I have a function:
fn = () => {
fn1(); // call first
fn2(); // call only when listener is done from fn1
}
and these two fns:
fn1 = () => {
const k1 = new Image();
k1.src = someSrc;
k1.addEventListener('load', () => some func {});
}
My question: What to do to make fn2 function fire only when fn1 is called and load event is fired?
const fn = async () => {
await fn1(); // call first
await fn2(); // call only when listener is done from fn1
}
const fn1 = async () => {
const k1 = new Image();
k1.src = await 'https://www.medicalnewstoday.com/content/images/articles/326/326253/corgi-and-terrier-running.jpg';
await k1.addEventListener('load', async () => await console.log('it should log first'));
}
const fn2 = async () => {
console.log('then second');
}
fn();
If you want to work with async/await, as mentioned in the comments, then you'll need to create and return a promise:
const fn1 = () => {
return new Promise((resolve) => {
const k1 = new Image();
k1.src = someSrc;
k1.addEventListener('load', resolve);
});
}
Then you can await this promise in an async function:
const fn = async () => {
await fn1();
fn2();
}
Try something like this:
const fn1 = () => {
const k1 = new Image();
k1.src = 'https://www.medicalnewstoday.com/content/images/articles/326/326253/corgi-and-terrier-running.jpg';
document.body.appendChild(k1);
return new Promise(resolve => {
k1.addEventListener('load', () => resolve('I am done!'));
})
}
const fn2 = () => {
console.log('then second');
}
const fn = async () => {
const a = await fn1(); // call first
console.log(a);
fn2(); // call only when listener is done from fn1
}
fn();
Why I can't access object properties with a . in async await return object?
I know that I can access the properties like below.
let val1 = await call(3);
let val2 = await call(4);
but I'm interested if this can be done
let v = await call(3).val + await call(4).val;
const call = (x) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
val: x
});
}, 3000)
})
}
const dummy = async () => {
//let val1 = await call(3);
//let val2 = await call(4);
//alert(value.val + val2.val);
let v = await call(3).val + await call(4).val;
alert(v);
}
dummy()
You're trying to await the value of the val property of the promise.
You need to await the promise and then read the val property from the result: (await call(3)).val
const call = (x) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
val: x
});
}, 3000)
})
}
const dummy = async () => {
let v = (await call(3)).val + (await call(4)).val;
alert(v);
}
dummy()
Just wrap the await and the expression to await in parens. Then access the property.
const call = (x) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
val: x
});
}, 3000)
})
}
const dummy = async() => {
let v = (await call(3)).val + (await call(4)).val;
alert(v);
}
dummy()
Do note that doing it this way, you're awaiting 3 seconds for the first call, then awaiting another 3 seconds for the second call. Unless the second call is somehow reliant on the first, I suggest you do the following:
const call = (x) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
val: x
});
}, 3000)
})
}
const dummy = async() => {
// Call both in parallel
let val1 = call(3);
let val2 = call(4);
// Await for both
let v = await Promise.all([val1, val2]);
// *then* add
alert(v[0].val + v[1].val);
}
dummy()
Why I can't access object properties with a . in async await return
object?
Because call returns a Promise and thus has no property val. When you await the returned Promise, the expression await call(x) will eventually resolve to {val: x}, which you can then use .val on.
Thus, you can either await each call separately and save the returned object in their own variables, or wrap your expression await call(x) in parenthesis of their own, such that you are getting the .val of the resolved value, not the promise:
const call = (x) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
val: x
});
}, 3000)
})
}
const dummy = async() => {
let v = (await call(3)).val + (await call(4)).val;
alert(v);
}
dummy()
This is because the call does not return a direct result object. It is returning a promise which will resolve value in .then callback. You can await this call.
const call = (x) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
val: x
});
}, 3000)
})
}
const dummy = async () => {
//let val1 = await call(3);
//let val2 = await call(4);
//alert(value.val + val2.val);
let v = await call(3).then(result => result.val) + await call(4).then((result)=> result.val);
alert(v);
}
dummy()