I can't figure out how to convert async await functionality in a while loop to a promise based implementation.
repl showing the async await version
https://repl.it/repls/IdealisticPepperyCoding
var dependency = false;
function checkDependency() {
return new Promise(resolve => {
setTimeout(() => {
dependency = true;
return resolve();
}, 1000)
});
}
async function isReady() {
while(!dependency) {
console.log('not loaded');
await checkDependency();
}
console.log('loaded')
}
isReady();
If I'm understanding you correctly, you're wanting to use Promises without async functions instead of Promises with async functions, and the sample checkDependency may actually not set dependency = true in all cases, so you want to "loop."
Equivalent functionality could look something like this, where you "recursively" call the check function. It won't actually be recursive and lead to a stack overflow, though, since the call is done in an async callback:
var dependency = false;
function checkDependency() {
return new Promise(resolve => {
setTimeout(() => {
dependency = true;
return resolve();
}, 1000)
});
}
function isReady() {
if (!dependency) {
return checkDependency().then(isReady);
}
return Promise.resolve(true);
}
isReady().then(() => {
console.log('loaded')
});
You don't need the while loop.
checkDependency().then(() => { console.log('loaded');});
You don't need to return recolve() just call it.
Call the function then within the function isReady
function checkDependency() {
return new Promise(resolve => {
setTimeout(resolve, 1000);
});
}
function isReady() {
console.log('not loaded');
checkDependency().then(() => {
console.log('loaded')
});
}
isReady();
Related
I'm trying to set a delay before every recursive function call. Currently, it's returning undefined. The problem might be the scope of the recursive call (inside settimeout and then).
I tried it like this:
function delay(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms)
});
}
const checkIfListElementIsRendered = (className) => {
delay(10).then(function (res) {
if (document.getElementsByClassName(className)[0]) {
return true;
}
return checkIfListElementIsRendered(className);
})
}
And this:
const checkIfListElementIsRendered = (className) => {
if (document.getElementsByClassName(className)[0]) {
return true;
}
setTimeout(() => {
return checkIfListElementIsRendered(className);
}, 10);
}
Any help is appreciated!
You need to turn checkIfListElementIsRendered to async/await syntax, and await the delay and checkIfListElementIsRendered methods, Also instead return true turn it to promise to be always return a promise.
When you call checkIfListElementIsRendered method outside, you need to resolve it with await or then callback.
function delay(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms)
});
}
const checkIfListElementIsRendered = async (className) => {
await delay(10)
if (document.getElementsByClassName(className)[0]) {
return Promise.resolve(true);
}
return await checkIfListElementIsRendered(className);
}
This question already has answers here:
Timeout in async/await
(3 answers)
Closed 1 year ago.
In my express application, I am making call to 2 APIs. The 2nd API is managed by 3rd party and sometimes can take more than 5 seconds to respond. Hence, I want to just wait for 1 second for the API to respond. If it does not, just proceed with data from 1st API.
Below is the mock-up of the functions being called.
I am thinking to use setTimeout to throw error if the API takes more than 1 second. If the API responds within 1 second then I just cancel the setTimeout and no error is ever thrown.
But there is problem with this approach:
setTimeout errors cannot be catched using try...catch block.
I cannot use axios's timeout option, as I still need to wait for the 2nd API to finish the processing and save the data in the DB. This will ofcourse, can happen later, when the 2nd API call finishes.
// Function to simulate it's taking time.
async function cWait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Track whether it took time.
let isTimeOut = false
async function test() {
console.log('starting')
try {
const one = await apiCall1()
const myt = setTimeout(() => {
console.log('Its taking time, skip the 2nd API Call')
isTimeOut = true
throw new Error('Its taking time')
})
const two = await apiCall2(myt)
} catch (error) {
console.log(error)
}
saveInDB({ ...one, ...two })
}
async function apiCall2(timeOutInstance) {
console.log('start-apiCall')
await cWait(1800)
clearTimeout(timeOutInstance)
if (isTimeOut) saveInDB()
console.log('done-apiCall')
}
async function apiCall1() {
await cWait(5)
}
async function saveInDB(data) {
console.log('saveInDB')
}
test()
please note, this is not the answer as it was when it was accepted
as I misread the question and failed to call saveInDB in a timed out
situation
Promise.race seems perfect for the job
Also, you'd actually use your cWait function, not for mock-up, but to actually do something useful ... win the race :p
const api2delay = 800;
async function cWait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
const TIMEDOUT = Symbol('TIMEDOUT');
async function cReject(ms) {
return new Promise((_, reject) => setTimeout(reject, ms, TIMEDOUT));
}
function apiCall2timeout(timeoutCallback) {
const resultApi2 = apiCall2();
const timeout = cReject(1000);
return Promise.race([resultApi2, timeout])
.catch(e => {
if (e === TIMEDOUT) {
resultApi2.then(timeoutCallback);
} else {
throw e;
}
});
}
async function test() {
console.log('starting')
let one, two;
try {
one = await apiCall1();
two = await apiCall2timeout(saveInDB);
} catch (error) {
console.log('error', error)
}
saveInDB({
...one,
...two
})
}
async function apiCall2() {
console.log('start-apiCall2')
await cWait(api2delay)
console.log('done-apiCall2')
return {
api2: 'done'
}
}
async function apiCall1() {
await cWait(5)
return {
api1: 'done'
}
}
async function saveInDB(data) {
console.log('saveInDB', data)
}
test()
Note: I changed where one and two were declared since const is block scoped
I you run with await cWait(800) in apiCall2, the saveInDB will run with both data.
But if you run await cWait(1800), the saveInDB will run 2 times.
// Function to simulate it's taking time.
async function cWait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// https://italonascimento.github.io/applying-a-timeout-to-your-promises/
const promiseTimeout = function (ms, promise) {
// Create a promise that rejects in <ms> milliseconds
let timeout = new Promise((resolve, reject) => {
let id = setTimeout(() => {
clearTimeout(id);
reject('Timed out in ' + ms + 'ms.')
}, ms)
})
// Returns a race between our timeout and the passed in promise
return Promise.race([
promise,
timeout
])
}
// Track whether it took time.
let isTimeOut = false
async function test() {
console.log('starting')
const one = await apiCall1() // get data from 1st API
let two = {};
try {
two = await promiseTimeout(1000, apiCall2())
} catch (error) {
isTimeOut = true;
console.log(error)
}
saveInDB({ ...one, ...two })
}
async function apiCall2() {
console.log('start-apiCall')
await cWait(800)
console.log('done-apiCall', isTimeOut)
if (isTimeOut) {
saveInDB({ 2: 'two' })
}
return { 2: 'two' }
}
async function apiCall1() {
await cWait(5)
return { 1: 'one' }
}
async function saveInDB(data) {
console.log('saveInDB', data)
}
test()
I am facing an issue while using async-await function in javascript.Let's have a look my code first.
function take() {
setTimeout(() => {
console.log('take order');
}, 4000);
}
function complete() {
setTimeout(() => {
console.log('complete order');
}, 20);
}
async function processOrder() {
let a = await take();
let b = await complete();
}
processOrder();
In the code above,I used await to control the order of the tasks.But it didn'twork.The complete function exicuted before the taks function.But I used await to wait in the task function to exicute and then the complete function exicution.
This is not a real life issue.I wonder what is going on here.Can anyone please explain it to me?
your functions are not using promise that's why it doesn't work!
function take() {
return new Promise(resolve => {
setTimeout(() => {
console.log('take order');
resolve()
}, 4000);
})
}
I have a simple yet perplexing issue with async functions.
I wish to simply return the value when its ready from the function.
Here is a sample code:
async function test() {
setTimeout(function() {
return 'eeeee';
}, 5000);
}
test().then(x => {
console.log(x)
});
You will get undefined been logged at once.
It's clear that you are trying to write a sleep() async function, but do remember that setTimeout is a sync function calling with a callback function will be executed at a given time, so while you are executing test(), the calling will run to end and return undefined as you have no return statement in the function body, which will be passed to your .then() function.
The right way to do this is to return a Promise that will be resolved after a given time, that will continue the then call.
async function sleep(time){
return new Promise((resolve,reject) => {
setTimeout(() => {
resolve("echo str")
},time)
})
}
sleep(5000).then((echo) => console.log(echo))
sleep function in short
const sleep = async time => new Promise(resolve=>setTimout(resolve,time))
With Promises
const setTimer = (duration) => {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Done!');
}, duration);
});
return promise;
};
setTimer(2000).then((res) => console.log(res));
An async function has to return a promise. So to fix this, you can wrap your setTimeout function in a new promise like so:
async function test(){
return await new Promise((resolve, reject) => {
setTimeout(function(){
resolve('eeeee');
},5000);
})
}
test().then(x => {
console.log(x)
});
You can learn more about async/await on the MDN docs here. Hope this helps!
I am just trying to understand how Promises and Async-Await work.
I want this to resolve by logging 1, 2, 3 in that order. Currently it logs 1, 3, 2.
I know the Promise doesn't really make sense here but in my program it has other uses so that needs to stay. The route from Caller function to Test also needs to stay (If need be you can change these but just know that they are there for a reason)
My question is how do I wait for the Caller function to resolve?
Here is my code:
function Test() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('2');
resolve();
}, 2000);
})
}
function Caller() {
Test();
}
console.log('1');
Caller();
console.log('3');
I have tried what I understand, which is to make the Caller() function await the Test Promise, but that of course makes the Caller() function async and therefore we still get 1, 3, 2
async function Caller() {
await Test();
}
Is there maybe some way to use await without making the function async?
You can only await a function that returns a promise (well, not quite true, if it doesn't return a promise it creates a promise that resolves instantly)
You can only await when you are inside an asynchronous function
function test() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('2');
resolve();
}, 2000);
})
}
async function caller() {
console.log('1');
await test();
console.log('3 (this is blocked awaiting the promise');
}
caller()
console.log("This is not blocked because caller is async");
This is a very straightforward, simple way of doing what you ask.
The await keyword can only be used inside functions
defined with async.
function test(ms) {
return new Promise((resolve, reject) => setTimeout(resolve, ms))
}
async function caller() {
console.log(1, ' - caller() started');
await test(2000).then(() => {
console.log(2, ' - test() resolved')
});
console.log(3, ' - delayed until "test()" has resolved');
return 4;
}
// wait for "caller()" to resolve
caller().then((result) => {
console.log(result, " - caller() finished")
});
console.log(5);
Here's a good article by Google which expands on the subject:
Async functions - making promises friendly.
Cite source.
here is how you could use functions like this:
function sleep(ms) {
return new Promise(r => {
setTimeout(() => r(), ms);
});
}
(async () => {
console.log(1);
await sleep(1000); // 1s
console.log(2);
await sleep(2000) // 2s
console.log(3)
})();
The previous answers are all correct but I just feel like this answer makes more sense. It is more accurate to the original question's code:
function Test() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('2');
resolve();
}, 2000);
})
}
function Caller() {
return Test();
}
(async() => {
console.log('1');
await Caller();
console.log('3');
})();