Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to wait for a function for a certain delay before executing the next function

Lets say i have two function i need to run

await func1()
await func2()

I want to wait for a maximum of 1000ms for func1() to complete. If it does not complete within the 1000ms then call func2(), don’t need to cancel the request for func1()

But if the func1() returns in less than 1000ms, let’s say 500ms, then it immediately executes the func2()

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I thought of trying some custom sleep function but not sure on how I would exit the sleep before hand.

>Solution :

You can use Promise.race() to clamp the execution time. It accepts multiple promises and returns a single one that will resolve as soon as the first of the promise arguments resolves:

const sleep = ms =>
  new Promise(resolve => setTimeout(resolve, ms));

//mock functions taking time
const func1 = () => sleep(100);  // 0.100s
const func2 = () => sleep(2000); // 2s
const func3 = () => sleep(300);  // 0.300s

//make a function that will clamp the wait time
const maxWait = ms => promise =>
  Promise.race([sleep(ms), promise]);

async function main() {
  const noMoreThan1Second = maxWait(1000);
  
  console.time("func1");
  await noMoreThan1Second(func1());
  console.timeEnd("func1");
  
  console.time("func2");
  await noMoreThan1Second(func2());
  console.timeEnd("func2");
  
  console.time("func3");
  await noMoreThan1Second(func3());
  console.timeEnd("func3");
}

main();

Note that Promise.race() will not cancel the task that the slower promise(s) are linked to. Since promises do not control asynchronous tasks, they are simply a notification mechanism. Therefore, using Promise.race() simply means ignoring the results of the slower promises. The async task they do would still continue in the background and can still succeed or fail. If rejections need to be handled, then nothing changes with Promise.race():

const sleep = ms =>
  new Promise(resolve => setTimeout(resolve, ms));

async function func() {
  console.log("func() started");
  await sleep(2000);
  console.log("func() finished");
}

async function main() {
  console.log("calling func()");
  await Promise.race([sleep(1000), func()]);
  console.log("finished waiting for func()");
}

main();

As a more advanced usage, default values might be returned if a promise is not resolved in time:

//allow optional value to be delayed
const sleep = (ms, value) =>
  new Promise(resolve => setTimeout(resolve, ms, value));

const maxWait = (ms, value) => promise =>
  Promise.race([sleep(ms, value), promise]);

const func1 = () => sleep(100, "one");
const func2 = () => sleep(2000, "two");

async function main() {
  const noMoreThan1Second = maxWait(1000, "default");
  
  console.log(await noMoreThan1Second(func1()));
  console.log(await noMoreThan1Second(func2()));
}

main();

Alternatively, there could be an error if something takes too long:

//allow optional value to be delayed
const sleep = (ms, value) =>
  new Promise(resolve => setTimeout(resolve, ms, value));
  
const delayedReject = (ms, value) =>
  new Promise((_, reject) => setTimeout(reject, ms, value));
  
const maxWait = (ms, value) => promise =>
  Promise.race([delayedReject(ms, value), promise]);

const func1 = () => sleep(100, "one");
const func2 = () => sleep(2000, "two");

async function main() {
  const noMoreThan1Second = maxWait(1000, "timeout");
  
  try {
    console.log(await noMoreThan1Second(func1()));
    console.log(await noMoreThan1Second(func2()));
  } catch(e) {
    console.log("problem encountered:", e)
  }
}

main();

As a small note, an alternative implementation of delayedReject() that re-uses sleep() would be:

const delayedReject = (ms, value) =>
    sleep(ms)
        .then(() => Promise.reject(value));

or shorter eta-reduced version:

const delayedReject = (ms, value) =>
    sleep(ms, value)
        .then(Promise.reject);
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading