-
-
Save mzabriskie/ec3a25dd45dfa0de92c2 to your computer and use it in GitHub Desktop.
/** | |
* The problem with using Promises for a request API is that Promises | |
* make it difficult to abort the request. Typically when using XHR | |
* some factory will wrap the actual XHR, but ultimately will return | |
* the XHR object. | |
* | |
* ``` | |
* var request = performRequest('/user/12345'); | |
* request.abort(); | |
* ``` | |
* | |
* Using Promises, the Promise is what's returned. | |
* | |
* ``` | |
* var promise = performRequest('/user/12345'); | |
* promise.then((response) => { console.log(response); }); | |
* ``` | |
* | |
* How then can the request be aborted? | |
* | |
* Working on axios (https://github.com/mzabriskie/axios), | |
* I get a lot of requests (no pun intended) for how to | |
* handle aborting a request once it's been made. This is | |
* a potential workaround for aborting a request when using | |
* XHR with Promises. | |
*/ | |
// Setup request config and initiate the request | |
var config = { | |
method: 'get', | |
url: '/user/12345' | |
}; | |
axios(config); | |
// Internally axios will add a requestID property to the | |
// request config. This is an auto incrementing integer | |
// that is unique to the request. | |
console.log(config); // {method: 'get', url: '/user/12345', requestID: 0} | |
// Now the request can be aborted by passing the requestID | |
// to axios.abort. Behind the scenes axios will have a | |
// collection of requests indexed by requestID. The request | |
// can then be aborted if it hasn't already been fulfilled. | |
// This is very similar to how setTimeout/clearTimeout works. | |
axios.abort(config.requestID); |
I disagree with aborting triggering an error @pluma. I think that it should do nothing.
axios({
url: '/some/url',
requestId: 'whatever'
}).then(function (res) {
console.log('Request was successful');
}).catch(function (res) {
console.log('An error occurred');
});
axios.abort('whatever');
In this case, nothing should be logged. It's not an error, so it shouldn't hit the catch
. At the same time it's obviously not a successful request so it shouldn't enter then
either. It should simply abort the request, as if it was never made.
I agree with @pluma about adding the method to the returned promise. How about this API:
var request = axios({
url: '/some/url',
});
request.then(function (res) {
console.log('Request was successful');
}).catch(function (res) {
console.log('An error occurred');
});
request.abort();
So, the API is one thing, and error handling is another.
any news on this? I believe it should reject the promise with an Abort state. How would it work with es7 async await, e.g:
const { data } = await axios({
url: '/some/url',
});
In case the promise doesn't get rejected the code about would stuck forever.
Agreed with @esnunes. Aborting it is an error in the fulfillment of the promise's goal (which was to "return" the response data). Just because it's developer-initiated it doesn't mean it's not an error in the request flow.
Agreed with @herrstucki's comment. cancelPreviousRequest
would be pretty useful!
This doesn't seem to work on 0.15.3
. Is there a way to do it now? I see there are cancellation tokens but I want to be able to prevent duplicate requests to the same URL from executing if one is still pending.
@mzabriskie Any updates on this, interested to. abort()
isn't an option in the latest, cancelPreviousRequest
would be useful. I know the latest supports cancelTokens now but they don't work for me.
What about just adding a cancel method to the promise it returns? Seems a lot more straightforward than keeping track of request IDs. Cancellable promises aren't entirely unheard of.
The promise should also be rejected with an error clearly indicating that the request was cancelled to allow checking this during error handling and not triggering the usual self-healing code one would trigger if the request failed due to a real error.