DEV Community

loading...
Cover image for Set a Time Limit on Async Actions

Set a Time Limit on Async Actions

ramko9999 profile image Ramki Pitchala Updated on ・3 min read

This article was originally posted on Medium. If you prefer reading it from there, please do check it out.

Introduction

Asynchronous programming is incredible!

With it, we can run our IO-intensive tasks without having to block the execution of other code.

However, in situations where the code after a blocking task depends on the task’s result, we must wait. Now, imagine if the blocking task took a long time to finish or it never finished. This could be problematic in the context of the application.

We can solve this issue by setting a time limit on our task. If our task doesn’t finish in the span of the time limit, we can return a failure value instead. Let me elaborate.

Concept

Let’s suppose that the blocking task is a promise called longTask, and it was used in the following function:

    async function doSomething(){
       let data = await longTask;
       doSomethingImportantWithData(data);
    }
Enter fullscreen mode Exit fullscreen mode

If the time it takes longTask to settle is longer than our requirements or if longTask is never settled, we won’t be able to execute the code after longTask in a timely manner.

However, imagine if we could set a time limit on our blocking tasks. In the case that the blocking task doesn’t settle within the time limit, we can return a failure value from the task. In the scenario the task resolves, we can return the value it resolved to.

To elaborate, suppose there was a function called fulfillWithTimeLimit which takes in milliseconds, the time limit, task, the task promise we would like to set a time limit on, and failureValue, the value that would be resolved from fulfillWithTimeLimit if task never completes within the time limit.

In the case that longTask is resolved before the time limit, fulfillWithTimeLimit returns with the value resolved from longTask.

In the case that longTask never finishes within the span of the time limit, the function should immediately return failureValue.

With this approach, we ensure that we never have to wait on longTask for more than the specified time limit.

Let’s dig into the approach.

Code

In order to “set a time limit” on the task, we can create another promise, timeoutPromise, which resolves to failureValue after the time limit. After that, we can race both our timeoutPromise and task with Promise.race.

Promise.race takes in a list of promises and resolves or rejects to the value of the promise in the list that is settled first.

To provide an example, suppose I had the two following promises:

    const a = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("A finished before!");
        }, 100);
    });

    const b = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("B finished!");
        }, 1000);
    });
Enter fullscreen mode Exit fullscreen mode

Suppose I raced these promises and got the value.

    const finishString = await Promise.race([a, b]);
Enter fullscreen mode Exit fullscreen mode

Since a resolves after 100 milliseconds while b resolves after 1000 milliseconds, a will be the first promise to resolve. As a result, finishString will be equal to “A finished before!”. If you would like to learn more about Promise.race, please check out the following:

Promise.race()

Nonetheless, let’s apply the promise racing idea to create the fulfillWithTimeLimit function.

To begin, we create our timeoutPromise and ensure it resolves with the failureValue after the time limit. Then, we race to see whether our task or timeoutPromise finishes first. For safety, we can clear the timeout and return response, the resolved value of the race.

Here is how doSomething looks now:

In the above example, I set failureValue to null. However, it may be better to set it to a value of the same type as what is resolved from the task. In fact, it may be better to call reject in the timeoutPromise than to resolve with a failureValue.

That’s it! We can easily reuse fulfillWithTimeLimit in our application code where we need a time limit.

Conclusion

In this blog, I aimed to show a solution with Promise.race to handle situations where blocking tasks may fail to settle or take too long to settle. Though I did not cover all the functionalities of promises, I hope this article amplifies your curiosity to explore them more.

Resources

Promise

Promise.race()

setTimeout

Discussion (2)

pic
Editor guide
Collapse
oskarcodes profile image
Oskar Codes

That is one really interesting use of Promise.race! Thank you for this article

Collapse
ramko9999 profile image
Ramki Pitchala Author

I appreciate it!