canceling the results of a promise
By Per Fröjd
- snippets
- react
- javascript
Dealing with long-running requests
In some of the React applications I’ve dealt with, I’ve come across long-running http requests, often tied tightly to the local state of a component. In some cases, these requests are to external APIs, and are often initiated after the component has mounted and simply updates a small part of the UI once the request has been finished.
Normally, most operations should be cancelled on the lifecycle event of componentWillUnmount
, but what if the request is still running by the time the component is being unmounted. In most cases, you’ll end up with a warning in the console regarding setting the state of an unmounted component, which isn’t the end of the world, but annoyed me enough to find a solution to the problem.
Wrapping the promises
NOTE: Original credit to the snippet should go to jimfb@github and alangpierce@github.com, found at the following issue.
const makeCancelable = (promise) => {
let hasCanceled = false
const wrappedPromise = new Promise((resolve, reject) => {
promise
.then((val) =>
hasCanceled ? reject({ isCanceled: true }) : resolve(val)
)
.catch((error) =>
hasCanceled ? reject({ isCanceled: true }) : reject(error)
)
})
return {
promise: wrappedPromise,
cancel() {
hasCanceled = true
},
}
}
Usage
// Wrap the promise
const longRunningPromise = makeCancelable(ExternalAPI.veryHeavyRequest());
// Execute it (more or less identical to how it would be done otherwise)
longRunningPromise
.promise
.then((returningData) => {
this.setState({
data: returningData
});
})
.catch({ hasCanceled, ...error }) => {
if (hasCanceled) {
// Promise has been canceled and shouldn't trigger any ordinary error-handling
return;
}
// Normal error-handling, notify the user etc..
});
// Now simply call the following .cancel() method.
longRunningPromise.cancel();
Final notes
This solution is definitely not the end-all, and there’s a bunch of different solutions found in the issue thread found here. This has worked without issue for me until something better comes along.