I am not an experienced Javascript programmer but I find it very difficult to execute 2 time-consuming functions in the row.
I have spent some days on studying promises or async/await but not success so far.
console.log("synch 1");
slowFunction1();
slowFunction2();
console.log("synch 2");
Most examples describe get json functions,setTimeOut etc. But in my case I have to do heavy mathematical calculations and the sequential execution is required. How could I do this?
Depends on what you're trying to achieve and what the environment is. I will assume the slow function is blocking and you're going for the main thread not to be blocked during execution. Assuming you are talking about:
Web:
Web workers would be your best bet (https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers)
Some example code would be:
var myWorker = new Worker('file-containing-slow-code.js');
myWorker.postMessage({execute: 'slowFunction1'});
myWorker.onmessage((msg) => {
const {result, functionExecuted} = msg.data;
console.log(result);
});
//contents of file-containing-slow-code.js
onmessage = function(e) {
var result = funcs[e.data.execute]();
postMessage({result, functionExecuted: e.data.execute});
}
const funcs = {
slowFunction1: () => {
// do slow stuff;
}
};
Node.js
Using child processes (https://nodejs.org/api/child_process.html#child_process_child_process)
You could wrap your functions in a promise like this, and only resolve when you want the code to continue:
function slowFunction1() {
return new Promise(resolve => {
setTimeout(() => resolve(), 1000)
})
}
function slowFunction2() {
return new Promise(resolve => {
setTimeout(() => resolve(), 1000)
})
}
console.log("synch 1");
slowFunction1().then(() => {
slowFunction2().then(() => {
console.log("synch 2");
});
})
This code should wait 1 second for each function before it console.log()'s "synch 2"
OR, you could use async/await instead of using .then(), like this:
function slowFunction1() {
return new Promise(resolve => {
setTimeout(() => resolve(), 1000)
})
}
function slowFunction2() {
return new Promise(resolve => {
setTimeout(() => resolve(), 1000)
})
}
async function main() {
console.log("synch 1");
await slowFunction1()
await slowFunction2()
console.log("synch 2");
}
main()
You got this right,you are trying to achieve a asychronous task.
Asynchronous Task
A task which will take some time to complete.
Way 1 - Callbacks
You need to give a callback to your further task.
Let me give you an example.
function myHugeTask(callback) {
// I need to do my task
console.log('Hey I am first task')
callback()
}
const someTaskWhichINeedToExecuteLater = () => {
console.log('Hey I am after the first task')
}
myHugeTask(someTaskWhichINeedToExecuteLater)
Way 2 - Promises
Promises is like a real world promise. If I promised you then I will either complete it or reject it.
Let see
const myHugeTaskPromise = new Promise(resolve => {
// Do my huge task no matter how much time it takes
console.log('I will complete first')
resolve()
})
myHugeTaskPromise.then(()=>{
console.log('Need to done when my promise get fulfilled')
})
Related
function first(){
console.log('first')
}
function second(){
console.log('second')
}
let interval = async ()=>{
await setInterval(first,2000)
await setInterval(second,2000)
}
interval();
Imagine that I have this code above.
When I run it, first() and second() will be called at the same time; how do I call second() after first)() returns some data, for example, if first() is done, only then call second()?
Because first() in my code will be working with a big amount of data and if this 2 functions will be calling at the same time, it will be hard for the server.
How do I call second() each time when first() will return some data?
As mentioned above setInterval does not play well with promises if you do not stop it. In case you clear the interval you can use it like:
async function waitUntil(condition) {
return await new Promise(resolve => {
const interval = setInterval(() => {
if (condition) {
resolve('foo');
clearInterval(interval);
};
}, 1000);
});
}
Later you can use it like
const bar = waitUntil(someConditionHere)
You have a few problems:
Promises may only ever resolve once, setInterval() is meant to call the callback multiple times, Promises do not support this case well.
Neither setInterval(), nor the more appropriate setTimeout() return Promises, therefore, awaiting on them is pointless in this context.
You're looking for a function that returns a Promise which resolves after some times (using setTimeout(), probably, not setInterval()).
Luckily, creating such a function is rather trivial:
async function delay(ms) {
// return await for better async stack trace support in case of errors.
return await new Promise(resolve => setTimeout(resolve, ms));
}
With this new delay function, you can implement your desired flow:
function first(){
console.log('first')
}
function second(){
console.log('second')
}
let run = async ()=>{
await delay(2000);
first();
await delay(2000)
second();
}
run();
setInterval doesn't play well with promises because it triggers a callback multiple times, while promise resolves once.
It seems that it's setTimeout that fits the case. It should be promisified in order to be used with async..await:
async () => {
await new Promise(resolve => setTimeout(() => resolve(first()), 2000));
await new Promise(resolve => setTimeout(() => resolve(second()), 2000));
}
await expression causes async to pause until a Promise is settled
so you can directly get the promise's result without await
for me, I want to initiate Http request every 1s
let intervalid
async function testFunction() {
intervalid = setInterval(() => {
// I use axios like: axios.get('/user?ID=12345').then
new Promise(function(resolve, reject){
resolve('something')
}).then(res => {
if (condition) {
// do something
} else {
clearInterval(intervalid)
}
})
}, 1000)
}
// you can use this function like
testFunction()
// or stop the setInterval in any place by
clearInterval(intervalid)
You could use an IFFE. This way you could escape the issue of myInterval not accepting Promise as a return type.
There are cases where you need setInterval, because you want to call some function unknown amount of times with some interval in between.
When I faced this problem this turned out to be the most straight-forward solution for me. I hope it help someone :)
For me the use case was that I wanted to send logs to CloudWatch but try not to face the Throttle exception for sending more than 5 logs per second. So I needed to keep my logs and send them as a batch in an interval of 1 second. The solution I'm posting here is what I ended up using.
async function myAsyncFunc(): Promise<string> {
return new Promise<string>((resolve) => {
resolve("hello world");
});
}
function myInterval(): void {
setInterval(() => {
void (async () => {
await myAsyncFunc();
})();
}, 5_000);
}
// then call like so
myInterval();
Looked through all the answers but still didn't find the correct one that would work exactly how the OP is asked. This is what I used for the same purpose:
async function waitInterval(callback, ms) {
return new Promise(resolve => {
let iteration = 0;
const interval = setInterval(async () => {
if (await callback(iteration, interval)) {
resolve();
clearInterval(interval);
}
iteration++;
}, ms);
});
}
function first(i) {
console.log(`first: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
function second(i) {
console.log(`second: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
(async () => {
console.log('start');
await waitInterval(first, 1000);
await waitInterval(second, 1000);
console.log('finish');
})()
In my example, I also put interval iteration count and the timer itself, just in case the caller would need to do something with it. However, it's not necessary
In my case, I needed to iterate through a list of images, pausing in between each, and then a longer pause at the end before re-looping through.
I accomplished this by combining several techniques from above, calling my function recursively and awaiting a timeout.
If at any point another trigger changes my animationPaused:boolean, my recursive function will exit.
const loopThroughImages = async() => {
for (let i=0; i<numberOfImages; i++){
if (animationPaused) {
return;
}
this.updateImage(i);
await timeout(700);
}
await timeout(1000);
loopThroughImages();
}
loopThroughImages();
Async/await do not make the promises synchronous.
To my knowledge, it's just a different syntax for return Promise and .then().
Here i rewrote the async function and left both versions, so you can see what it really does and compare.
It's in fact a cascade of Promises.
// by the way no need for async there. the callback does not return a promise, so no need for await.
function waitInterval(callback, ms) {
return new Promise(resolve => {
let iteration = 0;
const interval = setInterval(async () => {
if (callback(iteration, interval)) {
resolve();
clearInterval(interval);
}
iteration++;
}, ms);
});
}
function first(i) {
console.log(`first: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
function second(i) {
console.log(`second: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
// async function with async/await, this code ...
(async () => {
console.log('start');
await waitInterval(first, 1000);
await waitInterval(second, 1000);
console.log('finish');
})() //... returns a pending Promise and ...
console.log('i do not wait');
// ... is kinda identical to this code.
// still asynchronous but return Promise statements with then cascade.
(() => {
console.log('start again');
return waitInterval(first, 1000).then(() => {
return waitInterval(second, 1000).then(() => {
console.log('finish again');
});
});
})(); // returns a pending Promise...
console.log('i do not wait either');
You can see the two async functions both execute at the same time.
So using promises around intervals here is not very useful, as it's still just intervals, and promises changes nothing, and make things confusing...
As the code is calling callbacks repeatedly into an interval, this is, i think, a cleaner way:
function first(i) {
console.log(`first: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
function second(i) {
console.log(`second: ${i}`);
// If the condition below is true the timer finishes
return i === 5;
}
function executeThroughTime(...callbacks){
console.log('start');
let callbackIndex = 0; // to track current callback.
let timerIndex = 0; // index given to callbacks
let interval = setInterval(() =>{
if (callbacks[callbackIndex](timerIndex++)){ // callback return true when it finishes.
timerIndex = 0; // resets for next callback
if (++callbackIndex>=callbacks.length){ // if no next callback finish.
clearInterval(interval);
console.log('finish');
}
}
},1000)
}
executeThroughTime(first,second);
console.log('and i still do not wait ;)');
Also, this solution execute a callback every secondes.
if the callbacks are async requests that takes more than one sec to resolve, and i can't afford for them to overlap, then, instead of doing iterative call with repetitive interval, i would get the request resolution to call the next request (through a timer if i don't want to harass the server).
Here the "recursive" task is called lTask, does pretty much the same as before, except that, as i do not have an interval anymore, i need a new timer each iteration.
// slow internet request simulation. with a Promise, could be a callback.
function simulateAsync1(i) {
console.log(`first pending: ${i}`);
return new Promise((resolve) =>{
setTimeout(() => resolve('got that first big data'), Math.floor(Math.random()*1000)+ 1000);//simulate request that last between 1 and 2 sec.
}).then((result) =>{
console.log(`first solved: ${i} ->`, result);
return i==2;
});
}
// slow internet request simulation. with a Promise, could be a callback.
function simulateAsync2(i) {
console.log(`second pending: ${i}`);
return new Promise((resolve) =>{
setTimeout(() => resolve('got that second big data'), Math.floor(Math.random()*1000) + 1000);//simulate request that last between 1 and 2 sec.
}).then((result) =>{ // promise is resolved
console.log(`second solved: ${i} ->`,result);
return i==4; // return a promise
});
}
function executeThroughTime(...asyncCallbacks){
console.log('start');
let callbackIndex = 0;
let timerIndex = 0;
let lPreviousTime = Date.now();
let lTask = () => { // timeout callback.
asyncCallbacks[callbackIndex](timerIndex++).then((result) => { // the setTimeout for the next task is set when the promise is solved.
console.log('result',result)
if (result) { // current callback is done.
timerIndex = 0;
if (++callbackIndex>=asyncCallbacks.length){//are all callbacks done ?
console.log('finish');
return;// its over
}
}
console.log('time elapsed since previous call',Date.now() - lPreviousTime);
lPreviousTime = Date.now();
//console.log('"wait" 1 sec (but not realy)');
setTimeout(lTask,1000);//redo task after 1 sec.
//console.log('i do not wait');
});
}
lTask();// no need to set a timer for first call.
}
executeThroughTime(simulateAsync1,simulateAsync2);
console.log('i do not wait');
Next step would be to empty a fifo with the interval, and fill it with web request promises...
I was wondering what is the proper way to call a promise after another promise resolves. I know we can use async await to create functions which will resolve a promise. I was wondering which form of handling promises is consider proper practice, or is it good practice to create generators instead? consider the following code:
const fetchSomething = () => new Promise((resolve) => {
setTimeout(() => resolve(console.log('future value')), 500);
});
const fetchSomethingElse = () => new Promise((resolve) => {
setTimeout(() => resolve(console.log('future value dueeee')), 3000);
});
const get = () => {
return fetchSomething().then(function(){
fetchSomethingElse()
});
}
get();
or
const fetchSomething = () => new Promise((resolve) => {
setTimeout(() => resolve({resolve: true}), 500);
});
const fetchSomethingElse = () => new Promise((resolve) => {
setTimeout(() => resolve({resolve: true}), 3000);
});
const get = async function() {
const fet = await fetchSomething();
const fet2 = await fetchSomethingElse();
};
get();
Either one is fine. Your choice.
In the first you're nesting .then() handlers. In the second, you're using the newer await to sequence them. More people are moving to await because it appears to be simpler code for sequencing operations (assuming you do proper error handling), though in this case, they are pretty similar in complexity, particularly with the simplification suggested below so it's really up to your own personal coding style.
What is missing in both is that get() just returned a promise so you need to use .then() and .catch() with it to get the value and catch any errors.
Also, something that is missing in the first is that you aren't returning the second promise which means the caller won't know when the second operation is done.
Your first can be simplified and fixed up like this:
const get = () => {
return fetchSomething().then(fetchSomethingElse);
}
get().then(val => {
// done here
}).catch(err => {
// error here
});
As Pointy mentioned, you don't "call a promise". You "call a function that returns a promise". Promises are objects. They are not callable.
Probably what your title could be rewritten to is: "Correct way to sequence two asynchronous operations that each return a promise".
For completeness, if your two async operations don't depend upon one another, then you don't have to manually sequence them. You can start them both and then monitor when both are done. This will sometimes get a faster end-to-end response.
You can do that using Promise.all():
const get = function() {
return Promise.all([fetchSomething(), fetchSomethingElse()]).then(results => {
// process results array and then return final value
// results[0] is result from fetchSomething, results[1] is result from fetchSomethingElse
return finalVal;
});
}
Both are fine, but you are making a common mistake in the top example (and maybe it's just because of the simplification of the code for the question). You are returning the promise from get, but you are not returning the promise from the then. This means the caller of get won't know when both promises have resolved. Consider:
const fetchSomething = () => new Promise((resolve) => {
setTimeout(() => resolve(console.log('future value')), 500);
});
const fetchSomethingElse = () => new Promise((resolve) => {
setTimeout(() => resolve(console.log('future value dueeee')), 3000);
});
const get = () => {
return fetchSomething().then(function(){
fetchSomethingElse()
});
}
// we don't when fetchSomethingElse is done
get().then(() => console.log("done"));
Also there's another option you might consider since the second promise doesn't depend on the output of the first. Call them in parallel:
const get = () => {
return Promise.all([fetchSomething(), fetchSomethingElse() ])
}
In this case one can start before the other is finished and the whole operation should be faster.
It's important to remember that in Promise-based patterns you're using functions that return Promises. Promises are passed in resolve and reject arguments (which are themselves functions). What you resolve with, is what gets exectuted in the .then() phase, and what you reject with gets exectuted in the .catch() phase.
To handle Promises in sequence, you're passing your values into the top-level function that wraps the Promise.
so...
const p1 = () => {
return new Promise((resolve,reject) => {
window.setTimeout(() => {
resolve('future value one');
},500);
});
};
const p2 = (v1) => {
return new Promise((resolve,reject) => {
window.setTimeout(() => {
const v2 = 'future value two';
resolve({v1,v2});
},500);
});
};
p1().then(p2).then(console.log);
My need is simple. I would like to delay calls to sendEmail by 100 milliseconds. The email service provider permits at most sending 10 emails per second.
Note, however, though .map is synchronous, it immediately returns a Promise.
I have tried setTimeout to no avail, such as setTimeout(() => resolve(x), 100) and setTimeout(() => {return new Promise....}, 100).
Thoughts?
const promises = userEmailArray.map((userEmail) => {
return new Promise((resolve, reject) => {
....
mailer.sendEmail(userEmail);
return resolve();
});
});
});
...
Promise.all(promises).then(() => resolve()).catch(error => reject(error));
There are a bunch of different ways to approach this. I'd probably just use a recursive chained promise myself and then you can more precisely use a timer based on the finish from the previous call and you can use promises for calling it and handling propagation of errors.
I've assumed here that your mailer.sendEmail() follows the node.js callback calling convention so we need to "promisify" it. If it already returns a promise, then you can use it directly instead of the sendEmail() function that I created.
Anyways, here are a bunch of different approaches.
Recall Same Function After Delay (delayed recursion)
// make promisified version - assumes it follows node.js async calling convention
let sendEmail = util.promisify(mailer.sendEmail);
function delay(t, data) {
return new Promise(resolve => {
setTimeout(resolve.bind(null, data), t);
});
}
function sendAll(array) {
let index = 0;
function next() {
if (index < array.length) {
return sendEmail(array[index++]).then(function() {
return delay(100).then(next);
});
}
}
return Promise.resolve().then(next);
}
// usage
sendAll(userEmailArray).then(() => {
// all done here
}).catch(err => {
// process error here
});
Use setInterval to Control Pace
You could also just use a setInterval to just launch a new request every 100ms until the array was empty:
// promisify
let sendEmail = util.promisify(mailer.sendEmail);
function sendAll(array) {
return new Promise((resolve, reject) => {
let index = 0;
let timer = setInterval(function() {
if (index < array.length) {
sendEmail(array[index++]).catch(() => {
clearInterval(timer);
reject();
});
} else {
clearInterval(timer);
resolve();
}
}, 100);
})
}
Use await to Pause Loop
And, you could use await in ES6 to "pause" the loop:
// make promisified version - assumes it follows node.js async calling convention
let sendEmail = util.promisify(mailer.sendEmail);
function delay(t, data) {
return new Promise(resolve => {
setTimeout(resolve.bind(null, data), t);
});
}
// assume this is inside an async function
for (let userEmail of userEmailArray) {
await sendEmail(userEmail).then(delay.bind(null, 100));
}
Use .reduce() with Promises to Sequence Access to Array
If you aren't trying to accumulate an array of results, but just want to sequence, then a canonical ways to do that is using a promise chain driven by .reduce():
// make promisified version - assumes it follows node.js async calling convention
let sendEmail = util.promisify(mailer.sendEmail);
function delay(t, data) {
return new Promise(resolve => {
setTimeout(resolve.bind(null, data), t);
});
}
userEmailArray.reduce(function(p, userEmail) {
return p.then(() => {
return sendEmail(userEmail).then(delay.bind(null, 100));
});
}, Promise.resolve()).then(() => {
// all done here
}).catch(err => {
// process error here
});
Using Bluebird Features for both Concurrency Control and Delay
The Bluebird promise library has a couple useful features built in that help here:
const Promise = require('Bluebird');
// make promisified version - assumes it follows node.js async calling convention
let sendEmail = Promise.promisify(mailer.sendEmail);
Promise.map(userEmailArray, userEmail => {
return sendEmail(userEmail).delay(100);
}, {concurrency: 1}).then(() => {
// all done here
}).catch(err => {
// process error here
});
Note the use of both the {concurrency: 1} feature to control how many requests are in-flight at the same time and the built-in .delay(100) promise method.
Create Sequence Helper That Can Be Used Generally
And, it might be useful to just create a little helper function for sequencing an array with a delay between iterations:
function delay(t, data) {
return new Promise(resolve => {
setTimeout(resolve, t, data);
});
}
async function runSequence(array, delayT, fn) {
let results = [];
for (let item of array) {
let data = await fn(item);
results.push(data);
await delay(delayT);
}
return results;
}
Then, you can just use that helper whenever you need it:
// make promisified version - assumes it follows node.js async calling convention
let sendEmail = util.promisify(mailer.sendEmail);
runSequence(userEmailArray, 100, sendEmail).then(() => {
// all done here
}).catch(err => {
// process error here
});
You already have a 'queue' of sorts: a list of addresses to send to. All you really need to do now is pause before sending each one. However, you don't want to pause for the same length of time prior to each send. That'll result in a single pause of n ms, then a whole raft of messages being sent within a few ms of each other. Try running this and you'll see what I mean:
const userEmailArray = [ 'one', 'two', 'three' ]
const promises = userEmailArray.map(userEmail =>
new Promise(resolve =>
setTimeout(() => {
console.log(userEmail)
resolve()
}, 1000)
)
)
Promise.all(promises).then(() => console.log('done'))
Hopefully you saw a pause of about a second, then a bunch of messages appearing at once! Not really what we're after.
Ideally, you'd delegate this to a worker process in the background so as not to block. However, assuming you're not going to do that for now, one trick is to have each call delayed by a different amount of time. (Note that this does not solve the problem of multiple users trying to process large lists at once, which presumably is going to trigger the same API restrictions).
const userEmailArray = [ 'one', 'two', 'three' ]
const promises = userEmailArray.map((userEmail, i) =>
new Promise(resolve =>
setTimeout(() => {
console.log(userEmail)
resolve()
}, 1000 * userEmailArray.length - 1000 * i)
)
)
Promise.all(promises).then(() => console.log('done'))
Here, you should see each array element be processed in roughly staggered fashion. Again, this is not a scaleable solution but hopefully it demonstrates a bit about timing and promises.
It's simpler to just do an async iteration of the array.
function send(i, arr, cb) {
if (i >= arr.length) return cb();
mailer.sendEmail(arr[i]);
setTimeout(send, 100, i+1, arr, cb);
}
send(0, userEmailArray, function() { console.log("all done") });
How would you wait for a Promise to resolve/reject, for a maximum execution time ? The code below is obviously wrong, it's just to explain what I'm trying to achieve. I'm clueless.
await doSomething();
if ( executionTime > maxExecutionTime ) {
doSomethingElse();
}
This is not for a bluebird promise.
You can use Promise.race() which will immediately resolve/reject when the first promise in its iterable resolves or rejects. E.g.
const longTask = () => new Promise(resolve =>
setTimeout(() => resolve("Long task complete."), 300))
const timeout = (cb, interval) => () =>
new Promise(resolve => setTimeout(() => cb(resolve), interval))
const onTimeout = timeout(resolve =>
resolve("The 'maybeLongTask' ran too long!"), 200)
Promise.race([longTask, onTimeout].map(f => f())).then(console.log)
The only issue is you can't really cancel the 'longTask' just because of its long execution. In theory, you'd either set some flag (to tell it not to continue onto the next stage of its pipeline), or design your application with the consequences of the promise in mind.
See what happens when you swap the 200 and 300 intervals.
Edit: Per spsaucier's comment, I've delayed the execution of each promise until the Promise.line line.
The code below will give you some idea:
function doSomething(maxExecutionTime) {
return new Promise(resolve => {
setTimeout(() => resolve(true), 2000); // this setTimeout simulates your async action which sould not exced maxExecutionTime
setTimeout(() => resolve(false), maxExecutionTime);
});
}
async function someFunc(maxExecutionTime) {
var exced = await doSomething(maxExecutionTime);
if (exced) {
console.log("Doesn't exced max time");
} else {
console.log("Exced max time");
}
}
someFunc(1000);
someFunc(3000);
In ECMA6 You can do something like this:
let promise = new Promise((resolve, reject) => {
let wait = setTimeout(() => {
clearTimeout(wait);
resolve('Timed out after 200 ms..');
}, 200)
})
As noahnu suggested, you can use Promise.race. You can wrap it in a function that takes a promise.
With some syntax sugar you can use thisOrThat which takes logic, a function that takes 2 functions, first and second. You can apply logic here as to try the first function and when to try the second (in our case if the first doesn't resolve within a certain time then try the second).
thisOrThat then takes an argument first that is a function returning a promise (in our case doSomething.
thisOrThat returns an object that has an or property that takes a function returning a promise. That parameter is called second and is passed to logic as second (in our case it is doSomethingElse).
var timeoutPromise =
time =>
promiseFn =>
Promise.race([
promiseFn(),
new Promise(
(_,r)=>
setTimeout(
_=>r("timed out")
,time
)
)
]);
var thisOrThat =
logic =>
first => ({
or:second=>
logic(first)(second)
});
var within75ms = thisOrThat
(first=>second=>
timeoutPromise(75)(first)
.catch(_=>second())
);
var within25ms = thisOrThat
(first=>second=>
timeoutPromise(25)(first)
.catch(_=>second())
);
var doSomething = () =>
console.log("do something called")||
new Promise(r=>setTimeout(x=>r("something"),50));
var doSomethingElse = () =>
console.log("do something else called") ||
new Promise(r=>setTimeout(x=>r("something else"),50));
async function someFunc() {
const doesNotTimeOut =
await within75ms(doSomething).or(doSomethingElse);
console.log("within 75ms resolved to:",doesNotTimeOut);
const doesTimeOut =
await within25ms(doSomething).or(doSomethingElse)
console.log("within 25ms resolved to:",doesTimeOut);
};
someFunc();
I have used Promise.race
// Try to get config from mongo
async function getProjectConfigThreshold(projectName) {
function onTimeoutResolveDefaultThreshold() {
return new Promise(async (resolve) => {
setTimeout(() => {
resolve(DEFAULT_THRESHOLD);
}, 2000)
});
}
async function getThresholdFromProjectConfig() {
const projectConfig = await getProjectsConfig(projectName);
const threshold = projectConfig.threshold || DEFAULT_THRESHOLD;
return threshold;
}
return await Promise.race([getThresholdFromProjectConfig(), onTimeoutResolveDefaultThreshold()]);
}
Let say there's a promise. checkOnSomeValue() and for the first two seconds before the process is up the promise checkOnSomeValue() is rejected. Then after about two seconds the promise resolves a value.
Is there a way to wrap a promise so that the promise can be run every x milliseconds and then resolve the wrapper promise when the nested promise resolves?
Here is what I would do:
function poll(fn, ms) {
return fn().catch(e => Promise.delay(ms).then(() => poll(fn, ms)));
}
Basically, try the function, when it fails wait for ms milliseconds and then try again.
var polled = poll(checkOnSomeValue, 2000);
polled().then(v => {
// your resolved value here ^_^
});
Or with generators with const co = Promise.coroutine:
const poll = co(function*(fn, ms) {
while(true) {
try {
return yield fn();
} catch (e) {
yield Promise.delay(ms);
} // ignore rejections
}
});
Which lets you avoid the recursion.
Here's one way.
function waiter() {
return new Promise((resolve) => {
let interval = setInterval(() => {
return client.getBalanceAsync('*', 6)
.then(value => {
clearInterval(interval)
return resolve(value)
})
.catch((err) => {
})
}, 200)
})
}
I'd go basically with Benjamins answer, but in a slightly different implementation:
function poll(fn, ms) {
var resolve = () => fn().catch(retry);
var retry = () => Promise.delay(ms).then(resolve);
return resolve();
}
No big deal. But for some reason this ping-pong-implementation feels better/cleaner/more readable to me. Can't even argument why.