Here is one example function.
async function getRandomBig() {
let result;
result = await randomModule.getRandom();
if (result > 0.9 ) {
return getRandomBig();
} else {
return result;
}
}
So Obviously, I would like that execution to randomModule.getRandom() happens asynchronously. Is this example the way to go?
Also, I would like to know how to make the first call to getOutput be asynchronous.
Thank you
It's a little hard to answer your question given the info you've provided, but maybe this will help:
The async function will return a promise to the outside caller. Than means that results obtained from await will happen asynchronously. For example consider this code:
// normal synchronous function
function changeRes() {
return "after"
}
// sync function that `awaits` it's result
async function getget() {
res = await changeRes()
}
let res = "before"
// p will be a pending promise
var p = getget()
// what is res at this point?
console.log(res) // still "before" because await doesn't return until next tick
// now res is 'after'
p.then(() => console.log(res))
But be careful because the call to changeRes is not asynchronous — it is called in the current loop. Compare this with the first code. We only change the behavior of changeRes():
function changeRes() {
res = "after"
return res
}
async function getget() {
res = await changeRes()
}
let res = "before"
// p is still a pending promise
var p = getget()
// but res was changed in changeRes synchronously
console.log(res)
p.then(() => console.log(res))
EDIT based on comment:
With the recursive function, everything important is happening inside the async function, so it all should work as expected. For example, you can substitute your randomModule.getRandom with the regular Math.random() which is synchronous, but the await will make it work in the context of an async function. So this function will return a promise that resolves to a random float less than 0.25:
async function getRandomBig() {
let result;
result = await Math.random();
if (result > 0.25) {
return getRandomBig();
} else {
return result;
}
}
getRandomBig().then(console.log)
So will this even though it's truly async:
function asyncRandom(){
return new Promise(resolve => {
setTimeout(() => resolve(Math.random()), 500)
})
}
async function getRandomBig() {
let result;
result = await asyncRandom();
if (result > 0.25 ) {
console.log("too big recurse")
return getRandomBig();
} else {
return result;
}
}
getRandomBig().then(console.log)
Related
Suppose I have code like this:
let result = {
name: downloadNameFromInternetVerySlow(),
isFamous: determineIfNameIsFamous(this.name);
}
const downloadNameFromInternetVerySlow = () => {
path = "/home";
const folders = fs.readdirSync(path).filter(file => fs.lstatSync(path).isDirectory());
console.log(folders);
return folders[0];
}
downloadNameFromInternetVerySlow can take a long time, meanwhile determineIfNameIsFamous depends on downloadNameFromInternetVerySlow's result to return correct value.
How do I make sure determineIfNameIsFamous only runs after downloadNameFromInternetVerySlow is done?
The code you show is entirely synchronous so asynchronous results aren't actually the issue here like people were guessing. The issue is that this.name cannot be used to refer to a prior property in an object literal definition for several reasons, not the least of which this isn't set to the object you want.
Instead, you can do this:
let result = {};
result.name = downloadNameFromInternetVerySlow();
result.isFamous = determineIfNameIsFamous(result.name);
You can convert downloadNameFromInternetVerySlow to a Promise(if not already). and then user await to wait till it finished. Otherwise you can use Promise.then()
(This should be inside an async function)
let name = await downloadNameFromInternetVerySlow(),
let isFamous = determineIfNameIsFamous(this.name);
let result = {
name,
isFamous
}
Another method using Promise.then
let name, isFamous;
downloadNameFromInternetVerySlow().then(result => {
name = result;
isFamous = determineIfNameIsFamous(this.name);
});
Async/await
There’s a special syntax to work with promises in a more comfortable fashion, called “async/await”.
An async function returns a promise, like in this example:
const doSomethingAsync = () => {
return new Promise(resolve => {
setTimeout(() => resolve('I did something'), 3000)
})
}
When you want to call this function you prepend await, and the calling code will stop until the promise is resolved or rejected. One caveat: the client function must be defined as async. Here's an example :
const doSomething = async () => {
console.log(await doSomethingAsync())
}
function downloadNameFromInternetVerySlow(){
return new Promise(resolve => setTimeout(() => {
console.log("Set timeout resolving...");
return resolve("Sample Name");
}, 5000))
}
function determineIfNameIsFamous(name){
if(name === "Sample Name"){
return true;
}
return false;
}
async function myFunc(){
let result = {};
result.name = await downloadNameFromInternetVerySlow();
console.log(result);
result.isFamous = determineIfNameIsFamous(result.name);
return result;
}
myFunc().then(res => console.log("result : ", res))
Assuming downloadNameFromInternetVerySlow is asynchrononous (otherwise it would already work like you want), the solution is to use await.
Please note, to be able to do that, this code needs to be wrapped in an async function (or or top level with top level await available.)
async function getAndUseResult(){
let result = {
name: await downloadNameFromInternetVerySlow(),
isFamous: determineIfNameIsFamous(this.name)
}
console.log(JSON.stringify(result))
}
getAndUseResult();
My function below has await statements inside an if else.
If i do this function, it will return [] an empty array since it isnt waiting for the if else statement to finish.
How do I wait for the if else statement to finsih?
const [imageArray, setImageArray] = useState();
const [loading, setLoading] = useState(true);
let a = 1
var array = [];
if(a === 2){
array = await getArray();
} else if (a === 3){
array = await getArray2();
}
setImageArray(array);
setLoading(false);
render(
{(!loading) ? (
......
If i do this function, it will return [] an empty array since it isnt waiting for the if else statement to finish.
No, it won't. That's the point of async/await syntax, it lets you write asynchronous code using familiar flow control structures. The async function this code appears in will return a promise, and the settlement of that promise will depend on what happens in the function's logic. Your code will wait for the promise from getArray or getArray2 to settle, or will continue immediately if a isn't 1 or 2 since there's nothing to wait for.
How do I wait for the if else statement to finsih?
You don't have to, having await in the body of the if/else blocks is sufficient. The function's logic won't progress until the promise from getArray or getArray2 is settled, or (if a isn't 1 or 2) it won't wait because there's nothing to wait for.
Here's an example:
function delay(ms, value) {
return new Promise(resolve => {
setTimeout(resolve, ms, value);
});
}
async function getArray() {
await delay(400);
return [1];
}
async function getArray2() {
await delay(400);
return [2];
}
async function example(a) {
let array;
if (a === 1) {
console.log("Calling `getArray`");
array = await getArray();
} else if (a === 2) {
console.log("Calling `getArray2`");
array = await getArray2();
} else {
console.log("Not calling anything, a is not 1 or 2");
array = [3];
}
// Notice that this doesn't happen until/unless
// `getArray` or `getArray2`'s promise is fulfilled
console.log(`array is: ${JSON.stringify(array)}`);
}
const value = Math.floor(Math.random() * 3) + 1;
console.log(`Calling \`example(${value})\`...`);
example(value)
.then(() => {
console.log("`example` function's promise was fulfilled");
})
.catch(() => {
// (No code above rejects, but...)
console.log("`example` function's promise was rejected");
});
Run the snippet multiple times to see all three conditions occur (a = 1, 2, and 3).
I'm trying to run two promises with:
Promise.all([...])
But they both have their own .then:
Promise.all([promise1().then(...), promise2().then(...)])
And I wish to run another .then on the Promise.all, while also waiting for both .then to return if that makes any sense.
Here's a fiddle showing what I mean.
If you run
function get1() {
return new Promise((r)=>setTimeout(() => r(),3000))
}
function rejection() {/*Handle rejection*/}
function doAll(...ps) {
return Promise.all(ps.map(rejection))
}
(async () => {
var p1 = get1().then(()=>console.log("1"));
var p2 = get1().then(()=>console.log("2"));
Promise.all([p1, p2]).then(()=>{
console.log("3")
})
})()
then the result is the correct
1
2
3
If you run
function get1() {
return new Promise((r)=>setTimeout(() => r(),3000))
}
function rejection() {/*Handle rejection*/}
function doAll(...ps) {
return Promise.all(ps)
}
(async () => {
var p1 = get1().then(()=>console.log("1"));
var p2 = get1().then(()=>console.log("2"));
doAll(p1, p2).then(()=>{
console.log("3")
})
})()
then you again get the correct
1
2
3
As a result, the problem is with the part of ps.map(rejection). Let's see:
function get1() {
return new Promise((r)=>setTimeout(() => r(),3000))
}
function rejection() {/*Handle rejection*/}
function doAll(...ps) {
console.log(ps);
console.log(ps.map(rejection));
return Promise.all(ps.map(rejection));
}
(async () => {
var p1 = get1().then(()=>console.log("1"));
var p2 = get1().then(()=>console.log("2"));
doAll(p1, p2).then(()=>{
console.log("3")
})
})()
Output
The array of two elements, both being undefined is trivial to evaluate. Because ps.map(rejection) is an arrow function that names its parameter rejection and does not return anything.
if you want to work with async operation in javascript, there are 3 ways that you can use.
callback
Promise
async/await
In order to implement the exact thing that you want, the best and the optimized way is using the async/await method.
you can do it like this :
async function getAllData(){
const p1 = await promise1;
const p2 = await promise2;
}
now getAllData return Promise, you can use .then() to get the result and .catch() to get errors.
to read more about syntax and other features you can go to this site : explain about async and await
Question: With a Promise is there a mechanism to access the final return value in a .then() chain?
Background I need to run a series of checks/adjustments on an object. A few of the checks are asynchronous for example comparing data against stored data in mongodb. Because some checks are asynchronous I believe a Promise chain may be the correct option. However because the checks must be done in a specific order Promise.all() will not work. If a Promise chain is a possibility after all of the checks and adjustments have been made I'm not sure how to retrieve the object from the last .then() in the chain. Perhaps I'm approaching this problem with the wrong tool.
The following code is a simplified example. myObject passes through the chain of .then() statements but I'm not sure how to retrieve the final, updated object or if that's even possible.
function promisesPromises() {
return new Promise( function(resolve, reject) {
let x = {
name: 'super duper',
randomDataOne: 10000,
randomDataTwo: 5000
};
if (x) {
resolve(x);
} else {
reject('uh oh');
}
});
}
function firstAdjustment(myObject) {
myObject.randomDataOne += 1000;
return myObject
}
function secondAdjustment(myObject) {
myObject.randomDataTwo += 500;
return myObject;
}
promisesPromises()
.then(firstAdjustment)
.then(secondAdjustment);
I would give async/await a try to simplify things.
Note: async functions always return a promise. So in order to get to the data you need to await for the returned data inside another async function, or you need to use then(). I have given both examples in the code below.
function promisesPromises() {
return new Promise( function(resolve, reject) {
let x = {
name: 'super duper',
randomDataOne: 10000,
randomDataTwo: 5000
};
// Promise set to resolve after 5 seconds
if (x) {
setTimeout(() => {
resolve(x);
}, 5000)
} else {
reject('uh oh');
}
});
}
function firstAdjustment(myObject) {
myObject.randomDataOne += 1000;
return myObject
}
function secondAdjustment(myObject) {
myObject.randomDataTwo += 500;
return myObject;
}
const asyncFunction = async () => {
const myObject = await promisesPromises()
firstAdjustment(myObject)
secondAdjustment(myObject)
return myObject
}
// Example retrieving data with then()
asyncFunction().then(res => console.log("Example using then(): ", res))
// Example retrieving data inside async function
const anotherAsyncFunction = async () => {
const result = await asyncFunction()
console.log("Example using async(): ", result)
}
anotherAsyncFunction()
// Timer countdown to promise resolve
let count = 1
const timer = setInterval(() => {
console.log(count++)
if (count > 4) clearInterval(timer)
}, 1000)
I want to create a function that enqueues callback functions, but doesn't return until that callback has been dequeued and executed.
function executeCallback(callback) {
if( shouldEnqueue ) {
enqueue(callback);
// awaits execution of callback
// return executed callback's return value
} else {
return callback()
}
}
The actual function works as follows. When an orderbook is needed, we will check to see if we have a recent one cached. If we don't have a recent one, we will queue the request for a fresh orderbook. We will then return the orderbook once it has been requested. The actual code will look something like this:
const axios = require("axios");
const moment = require("moment");
const { promisify } = require("util");
const orderbookQueue = [];
const orderbookUpdateTime = {};
async function requestOrderbook(pair) {
const response = await axios.post("https://api.kraken.com/0/public/Depth", {
pair
});
orderbookUpdateTime[pair] = +moment();
return response.data.result[pair];
}
async function getOrderbook(pair, currentTime) {
if (
orderbookUpdateTime[pair] &&
currentTime - orderbookUpdateTime[pair] > 60000
) {
const requestOrderbookAsync = promisify(requestOrderbook);
orderbookQueue.push(() => requestOrderbookAsync(pair));
// how to I return the result of requestOrderbookAsync when it has been called ?
}
return requestOrderbook(pair);
}
const queueExecutor = function queueExecutor() {
while (orderbookQueue.length) {
orderbookQueue[0]();
orderbookQueue.shift();
}
};
1. Convert you callbacks to promise
E.g, convert
function mutilpy(a, b, callback) {
let result = a*b;
return callback(result);
}
to
function multiply(a, b) {
return new Promise(function(resolve, reject) {
let result = a*b;
resolve(result);
})
}
2. (Sort of) Enqueue your callbacks for completion
var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = multiply(10,3);
Promise.all([promise1, promise2, promise3]).then(function(values) {
// YOU GET HERE WHEN ALL PROMISES ARE RESOLVED
console.log(values);
});
// expected output: Array [3, 42, 30]
I found a solution that works for me. One can extract the resolve function from a new Promise, enqueue the resolve function in a different scope, then dequeue and execute the resolve function whenever the time comes, in any scope.
Resolve Javascript Promise outside function scope