mirror of
https://github.com/tenrok/axios.git
synced 2026-06-02 16:04:10 +03:00
Adding cancellation support
This commit is contained in:
@@ -185,6 +185,15 @@ module.exports = function httpAdapter(config) {
|
||||
}, config.timeout);
|
||||
}
|
||||
|
||||
if (config.cancelToken) {
|
||||
// Handle cancellation
|
||||
config.cancelToken.promise.then(function onCanceled(cancel) {
|
||||
req.abort();
|
||||
reject(cancel);
|
||||
aborted = true;
|
||||
});
|
||||
}
|
||||
|
||||
// Send the request
|
||||
if (utils.isStream(data)) {
|
||||
data.pipe(req);
|
||||
|
||||
@@ -153,6 +153,15 @@ module.exports = function xhrAdapter(config) {
|
||||
request.upload.addEventListener('progress', config.onUploadProgress);
|
||||
}
|
||||
|
||||
if (config.cancelToken) {
|
||||
// Handle cancellation
|
||||
config.cancelToken.promise.then(function onCanceled(cancel) {
|
||||
request.abort();
|
||||
reject(cancel);
|
||||
// Clean up request
|
||||
request = null;
|
||||
});
|
||||
}
|
||||
|
||||
if (requestData === undefined) {
|
||||
requestData = null;
|
||||
|
||||
@@ -34,6 +34,10 @@ axios.create = function create(defaultConfig) {
|
||||
return createInstance(defaultConfig);
|
||||
};
|
||||
|
||||
// Expose Cancel & CancelToken
|
||||
axios.Cancel = require('./cancel/Cancel');
|
||||
axios.CancelToken = require('./cancel/CancelToken');
|
||||
|
||||
// Expose all/spread
|
||||
axios.all = function all(promises) {
|
||||
return Promise.all(promises);
|
||||
|
||||
@@ -2,6 +2,16 @@
|
||||
|
||||
var utils = require('./../utils');
|
||||
var transformData = require('./transformData');
|
||||
var Cancel = require('../cancel/Cancel');
|
||||
|
||||
/**
|
||||
* Throws a `Cancel` if cancellation has been requested.
|
||||
*/
|
||||
function throwIfCancellationRequested(config) {
|
||||
if (config.cancelToken) {
|
||||
config.cancelToken.throwIfRequested();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch a request to the server using whichever adapter
|
||||
@@ -11,6 +21,8 @@ var transformData = require('./transformData');
|
||||
* @returns {Promise} The Promise to be fulfilled
|
||||
*/
|
||||
module.exports = function dispatchRequest(config) {
|
||||
throwIfCancellationRequested(config);
|
||||
|
||||
// Ensure headers exist
|
||||
config.headers = config.headers || {};
|
||||
|
||||
@@ -52,6 +64,8 @@ module.exports = function dispatchRequest(config) {
|
||||
// Wrap synchronous adapter errors and pass configuration
|
||||
.then(adapter)
|
||||
.then(function onFulfilled(response) {
|
||||
throwIfCancellationRequested(config);
|
||||
|
||||
// Transform response data
|
||||
response.data = transformData(
|
||||
response.data,
|
||||
@@ -60,16 +74,20 @@ module.exports = function dispatchRequest(config) {
|
||||
);
|
||||
|
||||
return response;
|
||||
}, function onRejected(error) {
|
||||
// Transform response data
|
||||
if (error && error.response) {
|
||||
error.response.data = transformData(
|
||||
error.response.data,
|
||||
error.response.headers,
|
||||
config.transformResponse
|
||||
);
|
||||
}, function onRejected(reason) {
|
||||
if (!(reason instanceof Cancel)) {
|
||||
throwIfCancellationRequested(config);
|
||||
|
||||
// Transform response data
|
||||
if (reason && reason.response) {
|
||||
reason.response.data = transformData(
|
||||
reason.response.data,
|
||||
reason.response.headers,
|
||||
config.transformResponse
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.reject(error);
|
||||
return Promise.reject(reason);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
var Cancel = axios.Cancel;
|
||||
var CancelToken = axios.CancelToken;
|
||||
|
||||
describe('cancel', function() {
|
||||
beforeEach(function() {
|
||||
jasmine.Ajax.install();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
jasmine.Ajax.uninstall();
|
||||
});
|
||||
|
||||
describe('when called before sending request', function() {
|
||||
it('rejects Promise with a Cancel object', function (done) {
|
||||
var source = CancelToken.source();
|
||||
source.cancel('Operation has been canceled.');
|
||||
axios.get('/foo', {
|
||||
cancelToken: source.token
|
||||
}).catch(function (thrown) {
|
||||
expect(thrown).toEqual(jasmine.any(Cancel));
|
||||
expect(thrown.message).toBe('Operation has been canceled.');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when called after request has been sent', function() {
|
||||
it('rejects Promise with a Cancel object', function (done) {
|
||||
var source = CancelToken.source();
|
||||
axios.get('/foo/bar', {
|
||||
cancelToken: source.token
|
||||
}).catch(function (thrown) {
|
||||
expect(thrown).toEqual(jasmine.any(Cancel));
|
||||
expect(thrown.message).toBe('Operation has been canceled.');
|
||||
done();
|
||||
});
|
||||
|
||||
getAjaxRequest().then(function (request) {
|
||||
// call cancel() when the request has been sent, but a response has not been received
|
||||
source.cancel('Operation has been canceled.');
|
||||
request.respondWith({
|
||||
status: 200,
|
||||
responseText: 'OK'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('calls abort on request object', function (done) {
|
||||
var source = CancelToken.source();
|
||||
var request;
|
||||
axios.get('/foo/bar', {
|
||||
cancelToken: source.token
|
||||
}).catch(function() {
|
||||
// jasmine-ajax sets statusText to 'abort' when request.abort() is called
|
||||
expect(request.statusText).toBe('abort');
|
||||
done();
|
||||
});
|
||||
|
||||
getAjaxRequest().then(function (req) {
|
||||
// call cancel() when the request has been sent, but a response has not been received
|
||||
source.cancel();
|
||||
request = req;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -11,7 +11,14 @@ describe('instance', function () {
|
||||
var instance = axios.create();
|
||||
|
||||
for (var prop in axios) {
|
||||
if (['Axios', 'create', 'all', 'spread', 'default'].indexOf(prop) > -1) {
|
||||
if ([
|
||||
'Axios',
|
||||
'create',
|
||||
'Cancel',
|
||||
'CancelToken',
|
||||
'all',
|
||||
'spread',
|
||||
'default'].indexOf(prop) > -1) {
|
||||
continue;
|
||||
}
|
||||
expect(typeof instance[prop]).toBe(typeof axios[prop]);
|
||||
|
||||
@@ -320,5 +320,21 @@ module.exports = {
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
testCancel: function(test) {
|
||||
var source = axios.CancelToken.source();
|
||||
server = http.createServer(function (req, res) {
|
||||
// call cancel() when the request has been sent, but a response has not been received
|
||||
source.cancel('Operation has been canceled.');
|
||||
}).listen(4444, function() {
|
||||
axios.get('http://localhost:4444/', {
|
||||
cancelToken: source.token
|
||||
}).catch(function (thrown) {
|
||||
test.ok(thrown instanceof axios.Cancel, 'Promise must be rejected with a Cancel obejct');
|
||||
test.equal(thrown.message, 'Operation has been canceled.');
|
||||
test.done();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user