Promisify a function call with timeouts
I have seen many resources provide similar examples of using Promise.race
to timeout a function call within a given period of time. This is a very good example of how Promise.race
can be used in practice. Here's some sample code:
function doWithinInterval(func, timeout) {
var promiseTimeout = new Promise(function (fulfill, reject) {
// Rejects as soon as the timeout kicks in
setTimeout(reject, timeout);
});
var promiseFunc = new Promise(function (fulfill, reject) {
var result = func(); // Function that may take long to finish
// Fulfills when the given function finishes
fulfill(result);
});
return Promise.race([promiseTimeout, promiseFunc]);
}
The simple approach above using Promise.race
rejects the promise as soon as the timeout kicks in before func
has completed. Otherwise, the project is fulfilled once the func
function finishes before the timeout interval.
This sounds good and easy to use.
However, is this the best practice to use timeout in Promise?
Surely, the approach above can be employed if we want to set a timeout against a function call using Promises. The operations still appear to be a good promise. However, is this considered a good practice of using timeout in a Promise? If not, what is the disadvantage of using this?
I've look for alternative approaches, but couldn't find a native Promise way to do this.
Instead, some external Promise libraries offer timeout
functionality as follows:
Bluebird supplies .timeout()
WinJS supplies .timeout()
as well
Q also comes with .timeout()
.
However, Promise.timeout()
doesn't appear to be part of the standard ECMAScript 6 API (please correct me if I'm wrong). Is there any recommended way to handle timeouts natively with ES6 Promises?
setTimeout() is not exactly a perfect tool for the job, but it's easy enough to wrap it into a promise: const awaitTimeout = delay => new Promise(resolve => setTimeout(resolve, delay)); awaitTimeout(300). then(() => console. log('Hi')); // Logs 'Hi' after 300ms const f = async () => { await awaitTimeout(300); console.
The reason the promise is executing before your timeout is that the promise isn't actually waiting for anything so it resolved right away. @frankies That has more to do with the way Promises are queued and resolved. The focus of my answer is the difference between setTimeout and Promise .
all() The Promise. all() method takes an iterable of promises as an input, and returns a single Promise that resolves to an array of the results of the input promises. This returned promise will fulfill when all of the input's promises have fulfilled, or if the input iterable contains no promises.
Promise callbacks are handled as a Microtask whereas setTimeout() callbacks are handled as Task queues.
It depends on what you mean by timeout.
If you expect the function to stop, then no.
If you just want to stop waiting for it, then yes (quick to whip up in ES6):
var wait = ms => new Promise(resolve => setTimeout(resolve, ms));
var timeout = (p, ms) => Promise.race([p, wait(ms).then(() => {
throw new Error("Timeout after " + ms + " ms");
})]);
var wait = ms => new Promise(resolve => setTimeout(resolve, ms));
var timeout = (p, ms) => Promise.race([p, wait(ms).then(() => {
throw new Error("Timeout after " + ms + " ms");
})]);
// Example:
var log = msg => div.innerHTML += "<p>" + msg + "</p>";
var failed = e => log(e.toString() + ", line " + e.lineNumber);
log("Waiting 5 seconds...");
timeout(wait(5000), 2000)
.then(() => log("...Done."))
.catch(failed);
<div id="div"></div>
If you want to cancel the operation (make it stop), then hopefully that operation comes with an API to cancel it, and you should use that, since an ES6 promise is not a control surface.
Cancelable promises is a controversial topic in ES6, but some of the libraries mentioned do offer the concept.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With