I have a few promises that I have to iterate with the generator. I created the helper function that prints the first promise but I have difficulties creating an iterator in a helper function to iterate all promises. I actually don't understand how constant a, constant b, and constant c can be iterated.
const asyncTask1 = () => new Promise((resolve, reject) => setTimeout(() => resolve('first resolved'), 1000));
const asyncTask2 = () => new Promise((resolve, reject) => setTimeout(() => resolve('second resolved'), 1000));
const asyncTask3 = () => new Promise((resolve, reject) => setTimeout(() => reject('third rejected'), 1000));
async function helper(func) {
let p = func().next().value
let output = await p
console.log(output)
}
helper(function* main() {
try {
const a = yield asyncTask1()
console.log(a);
const b = yield asyncTask2()
console.log(b);
const c = yield asyncTask3()
} catch (e) {
console.error('error happened', e);
}
})
Output: first resolved
Should be:
first resolved
second resolved
third rejected
You are calling the generator only once using .next() only once so the function would yield only once. Also, when you can func() you are creating a new generator every time. Your try catch block is in generator inside which is yield, so it won't catch the error since yield would not throw an error. Finally, third task will not be a success, it will throw an error as it is rejected.
I will do it as below -
const asyncTask1 = () => new Promise((resolve, reject) => setTimeout(() => resolve('first resolved'), 1000));
const asyncTask2 = () => new Promise((resolve, reject) => setTimeout(() => resolve('second resolved'), 1000));
const asyncTask3 = () => new Promise((resolve, reject) => setTimeout(() => reject('third rejected'), 1000));
async function execute() {
try {
const iterator = generator();
let p = iterator.next().value;
let output = await p;
console.log(output);
let q = iterator.next().value;
let output1 = await q;
console.log(output1);
let r = iterator.next().value;
let output2 = await r;
console.log(output3);
} catch (e) {
console.log('error happened', e);
}
}
const generator = function* generator() {
yield asyncTask1();
yield asyncTask2();
yield asyncTask3();
}
execute();
Referring to #Felix Kling's comment, a more elegant way to do this would be -
const asyncTask1 = () => new Promise((resolve, reject) => setTimeout(() => resolve('first resolved'), 1000));
const asyncTask2 = () => new Promise((resolve, reject) => setTimeout(() => resolve('second resolved'), 1000));
const asyncTask3 = () => new Promise((resolve, reject) => setTimeout(() => reject('third rejected'), 1000));
async function execute() {
const iterator = generator();
for await (const task of iterator) {
try {
let output = await task();
console.log(output);
} catch (e) {
console.log('error happened', e);
}
}
}
const generator = function* generator() {
yield*[asyncTask1, asyncTask2, asyncTask3];
}
execute();
Related
Result: a, b, d, c.
Expected: a, b, c, d
const promises = []
console.log('a')
someFunc(promises)
Promise.allSettled(promises).then(() => console.log('d'))
function someFunc(promises) {
const promise = new Promise(resolve => setTimeout(() => {
console.log('b')
const promise2 = new Promise(resolve2 => setTimeout(() => {
console.log('c')
resolve2()
}, 3000))
promises.push(promise2)
resolve()
}, 3000))
promises.push(promise)
return promise
}
While it'd be possible to patch it up by not pushing to an array, but instead having each Promise chain off of each other in someFunc...
console.log('a')
someFunc().then(() => console.log('d'))
function someFunc() {
return new Promise(resolve => setTimeout(() => {
console.log('b')
new Promise(resolve2 => setTimeout(() => {
console.log('c')
resolve2()
}, 3000))
.then(resolve);
}, 3000))
}
A much more understandable version would promisify setTimeout to begin with instead of doing it every time.
const setTimeoutPromise = ms => new Promise(resolve => setTimeout(resolve, ms));
console.log('a')
someFunc().then(() => console.log('d'))
function someFunc() {
return setTimeoutPromise(3000)
.then(() => {
console.log('b');
return setTimeoutPromise(3000)
})
.then(() => {
console.log('c');
return setTimeoutPromise(3000)
});
}
Which can be further simplified with await...
const setTimeoutPromise = ms => new Promise(resolve => setTimeout(resolve, ms));
console.log('a')
someFunc().then(() => console.log('d'))
async function someFunc() {
await setTimeoutPromise(3000);
console.log('b');
await setTimeoutPromise(3000);
console.log('c');
await setTimeoutPromise(3000);
}
Solution
I know you may be confused on this question a lot. Here is the solution I found
const promises = []
const timeout = ms => {
const promise = new Promise(resolve => setTimeout(resolve, ms))
promises.push(promise)
return promise
}
const someFunc = () =>
timeout(1000).then(() => {
console.log('b')
timeout(1000).then(() => console.log('c'))
})
async function main() {
console.log('a')
someFunc()
let i = 0;
while (promises.length > i) {
i = promises.length
await Promise.allSettled(promises)
}
console.log('d')
}
main()
The problem I really want to express is that the content of the function someFunc is not determined at compile time while I need to make sure that the function leave no side effect once executed.
I'm trying to use async/await for a very basic promise, but I'm getting the error: SyntaxError: await is only valid in async function. However, I believe I'm using await for an async function.
function getNumber(mult) {
return new Promise((resolve, reject) => {
resolve(10);
}).then((val) => {
return new Promise((resolve, reject) => {
resolve(val * mult)
//reject("Error");
}).then((val2) => val2);
}).catch((err) => {
return err;
})
}
const calculate = async (x) => await Promise.resolve(getNumber(x))
const val = await calculate(2)
You cannot have the initial function with an await at the top level... just a modification.
function getNumber(mult) {
return new Promise((resolve, reject) => {
resolve(10);
}).then((val) => {
return new Promise((resolve, reject) => {
resolve(val * mult)
//reject("Error");
}).then((val2) => val2);
}).catch((err) => {
return err;
})
}
const calculate = (x) => Promise.resolve(getNumber(x));
const val = calculate(2).then(resp => {
console.log('do something with response: ', resp)
})
To only focus on why you're getting that error, the await in await calculate(2) isn't in an asynchronous function. If you can make it asynchronous function then do that but if not then you can use the .then() function like below:
calculate(2).then(val => {
//Your code here
}
First of all I'm sorry I'm a very beginner in JS. The following code stucks at the third line. In the background_mine method. I don't have access to this method, so how can I reset the code after 2 minutes stucking in this method
Mining = async () => {
console.log(`## rebalance: ${await getBalance(account, wax.api.rpc)}`);
let mine_work = await background_mine(account)
}
You may need to do a Promise.race
Example working properly:
const background_mine = new Promise(function(resolve, reject) {
setTimeout(() => resolve('background_mine'), 500);
});
const limitChecker = new Promise(function(resolve, reject) {
setTimeout(() => resolve('background_failed'), 1000);
});
const result = await Promise.race([background_mine, limitChecker])
.catch((error) => {
console.log(`This timed out`);
});
console.log(result); //background_mine
Example having a timeout:
const background_mine = new Promise(function(resolve, reject) {
setTimeout(() => resolve('background_mine'), 500);
});
const limitChecker = new Promise(function(resolve, reject) {
setTimeout(() => resolve('background_failed'), 1000);
});
const result = await Promise.race([background_mine, limitChecker])
.catch((error) => {
console.log(`This timed out`);
});
console.log(result); //undefined
If you check, it all depends on wether background_mine functions is below or above the limitChecker timeout value.
In order to implement a timeout, you can use Promise.race like this:
const background_mine = account => new Promise(() => {});
const promisifiedTimeout = new Promise((resolve, reject) => setTimeout(() => reject('Timed out'), 5000));
(async () => {
const account = {};
try {
const result = await Promise.race([background_mine(account), promisifiedTimeout]);
}
catch(e) {
console.log(e);
}
})();
I am trying to get all the results from a map with time out.
I’ve tried to use promise.all() But it didn’t succeed because of the setTimeout function.
I will be happy if someone can look oh my code and suggest how to do it right.
Thank you very much.
new Promise(async (resolve, reject) => {
Promise.all(
items.map(async (item, i) => {
await setTimeout(async () => {
return await SendMail(item);
}, 5000 * i);
})
).then((mailsRes) => {
resolve(mailsRes);
});
});
Simply loop through your items and sleep for x seconds (5 in this example) after sending each email.
const sleep = (milliSeconds) => {
return new Promise((resolve, _reject) => {
setTimeout(() => {
resolve()
}, milliSeconds)
})
}
const sendEmails = async (items) => {
for (let i = 0; i < items.length; i++) {
const currentItem = items[i];
await SendMail(currentItem);
await sleep(5000)
}
}
as you see sendEmails is an async function then you can call it by:
await sendEmails(items)
Not sure what you are trying to achieve but you probably need this-
async function timeout(interval) {
return new Promise(resolve => {
setTimeout(resolve, interval);
});
}
new Promise( async (resolve, reject) => {
Promise.all(items.map( async (item, i)=>{
await timeout(5000 * i).then(() => {
return await SendMail(item);
});
}))
.then(mailsRes => {
resolve(mailsRes)
})
});
The problem is that setTimeout is resolved immediately and you get a timeout canceller in the next callback.
If I understand you correctly, that might do the trick:
function delayedSendMail(item, i) {
return new Promise(resolve => setTimeout(() => resolve(SendMail(item)), 5000 * i));
}
Promise.all(items.map((item, i) => delayedSendMail(item, i)))
.then(mailResults => {
// handle results
});
I have a use case, where I am doing an external API call from my code,
The response of the external API is required by my code further on
I am bumping into a scenario, where the external API call at times takes far too long to return a response,
casing my code to break, being a serverless function
So I want to set a time limit to the external API call,
Where if I don't get any response from it within 3 secs, I wish the code to gracefully stop the further process
Following is a pseudo-code of what I am trying to do, but couldn't figure out the logic -
let test = async () => {
let externalCallResponse = '';
await setTimeout(function(){
//this call sometimes takes for ever to respond, but I want to limit just 3secs to it
externalCallResponse = await externalCall();
}, 3000);
if(externalCallResponse != ''){
return true;
}
else{
return false;
}
}
test();
Reference -
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SSM.html#getParameters-property
I'm using AWS SSM's getParameters method
You cannot await setTimeout as it doesn't returns a Promise.
You could implement a function that returns a Promise which is fulfilled after 3 seconds.
function timeout(seconds) {
return new Promise((resolve) => {
setTimeout(resolve, seconds * 1000)
});
}
You can await the above function in your code passing the number of seconds you want to wait for
let test = async () => {
let externalCallResponse = '';
setTimeout(async () => {
externalCallResponse = await externalCall();
}, 0);
await timeout(3); // wait for 3 seconds
if(externalCallResponse != '') return true;
else return false;
}
Following code snippet demonstrates the usage of timeout function written above. It mocks a api request that returns a response after 4 seconds.
function timeout(seconds) {
return new Promise(resolve => {
setTimeout(resolve, seconds * 1000);
});
}
function apiRequest() {
return new Promise(resolve => {
setTimeout(() => resolve('Hello World'), 4000);
});
}
let test = async () => {
let externalCallResponse = '';
setTimeout(async () => {
externalCallResponse = await apiRequest();
}, 0);
await timeout(3); // wait for 3 seconds
if (externalCallResponse != '') return true;
else return false;
};
test()
.then(res => console.log(res))
.catch(err => console.log(err.message));
you can use something like this, I created a function that return a promise then I used this promise.
let test = async () => {
return promiseTimeout()
}
const promiseTimeout = () => {
return new Promise(async (resolve, reject) => {
setTimeout(function () {
let externalCallResponse=""
externalCallResponse = await externalCall();
if (externalCallResponse != '') {
return resolve(true);
}
else {
return resolve(false);
}
}, 3000);
})
}
test().then(result=>{
console.log(result);
});
You could do something like this:
const timeout = async (func, millis) => {
return new Promise(async (resolve, reject) => {
setTimeout(() => reject(), millis);
resolve(await func());
});
}
timeout(() => doStuff(), 3000)
.then(() => console.log('worked'))
.catch(() => console.log('timed out'));
Tests:
const timeout = async (func, millis) => {
return new Promise(async (resolve, reject) => {
setTimeout(() => reject(), millis);
resolve(await func());
});
}
const doStuffShort = async () => { // Runs for 1 second
return new Promise((resolve) => setTimeout(() => resolve(), 1000));
}
const doStuffLong = async () => { // Runs for 5 seconds
return new Promise((resolve) => setTimeout(() => resolve(), 5000));
}
timeout(() => doStuffShort(), 3000)
.then(() => console.log('1 worked'))
.catch(() => console.log('1 timed out'));
timeout(() => doStuffLong(), 3000)
.then(() => console.log('2 worked'))
.catch(() => console.log('2 timed out'));