Interface Analysis
https://github.com/axios/axio...
Usage 1
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.post('/user/12345', {
name: 'new name'
}, {
cancelToken: source.token
}).catch(function (thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// handle error
}
});
source.cancel('Operation canceled by the user.');
Mode 2
const CancelToken = axios.CancelToken;
let cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
cancel = c;
})
});
cancel();
Is to add cancelToken Parameters , The value can be an object , There are operations that can be cancelled .
Source code analysis
Refer to the use case , location
axios.CancelToken
, To find the source code
https://github.com/axios/axio...isCancel.js Determine whether cancel object module.exports = function isCancel(value) { return !!(value && value.__CANCEL__); };
Cancel.js structure cancel object , Used to identify cancel Of message Information function Cancel(message) { this.message = message; } Cancel.prototype.toString = function toString() { return 'Cancel' + (this.message ? ': ' + this.message : ''); }; Cancel.prototype.__CANCEL__ = true; module.exports = Cancel;
CancelToken.js var Cancel = require('./Cancel'); function CancelToken(executor) { // The actuator must be a function if (typeof executor !== 'function') { throw new TypeError('executor must be a function.'); } var resolvePromise; // Create a promise, And record resolve Method , For use in actuators this.promise = new Promise(function promiseExecutor(resolve) { resolvePromise = resolve; }); var token = this; // cancel The core method of : use reason To record the cancellation reason , And used to determine whether it has been cancelled . and resolve Drop the top promise executor(function cancel(message) { if (token.reason) { // Cancellation has already been requested return; } token.reason = new Cancel(message); resolvePromise(token.reason); }); } // Judge whether it has been cancelled , If it's cancelled , The reason for cancellation is thrown CancelToken.prototype.throwIfRequested = function throwIfRequested() { if (this.reason) { throw this.reason; } }; // Static methods , Return an instance // The essence of mode 2 is the following implementation CancelToken.source = function source() { var cancel; var token = new CancelToken(function executor(c) { cancel = c; }); return { token: token, cancel: cancel }; }; module.exports = CancelToken;
Search code cancelToken, location ib/core/dispatchRequest.js
function throwIfCancellationRequested(config) { if (config.cancelToken) { config.cancelToken.throwIfRequested(); } }
- trace
throwIfCancellationRequested
Where to call , Click on the functionthrowIfCancellationRequested
, Press F12, See where the call is
in other words , At initialization time 、 When the request succeeds and when the request fails , Determine whether the request has been initiated , If initiated , The reason for cancellation is thrown .
Solved the problem of user calling cancel The timing of , Before the request is initiated, the request is intercepted , After the request is made , Whatever the outcome , Will no longer enter the processing logic . - Follow up , By promisify Of xhr/http
Code shows , Before making a request , Judge whether it's passed cancelToken. If you pass in , Then add cancelToken Of promise Callback , Cancel the request . Pay attention to CancelToken.js, hold cancel The method is exposed , The user calls cancel After the method, you will promise resolve fall .
Recombing
- xhr/http, Before making a request , Determine if there is an incoming cancelToken, Also on promise Incoming callback , The origination of the intercept request . therefore CancelToken.js There needs to be one promise inform xhr/http Whether the user has executed cancel 了 .
- dispatchRequest.js, Initializing 、 The request is successful 、 When the request fails , Judge whether it has been cancel 了 , If so, throw an error . So we need to CancelToken.js A variable to determine whether it has been cancel too , And one. throwIfRequested Method to judge .
- call cancel The moment of , Users may want to do some custom operations . Therefore, the actuator can be passed in by the user , Or provide a static method to create a new instance , And the actuator has been written .
What is worth learning
promise We often call it according to the standard method , stay promise Perform... In vivo resolve,reject
new Promsie((resolve, reject) => { ... if (...) { resolve('xxx') } else { reject('yyy') } })
In fact, you can be flexible , Use variables to save resolve/reject, Perform... Outside , Increase flexibility .
let resolver; new Promsie((resolve, reject) => { ... resolver = resolve; }) ... resolver('xxx') ...
The argument to a function is a function , You need to understand why it can be called by the user , Direct use t To express CancelToken.js The actuator that has been written
function CancelToken(executor) { ... // executor Function call executor(function cancel(message) { if (token.reason) { return; } token.reason = new Cancel(message); resolvePromise(token.reason); }); ... } CancelToken.source = function source() { var cancel; // executor Function definition var token = new CancelToken(function executor(c) { cancel = c; }); return { token: token, cancel: cancel }; };
To simplify the
var cancel; // Function definition function executor(c) { cancel = c; } // Function call execotr(() => {console.log('abc'})
in other words , When defining functions , Save a global variable to the information of local variables , This is to reference the information passed in by the user .
Because there are variable references , So I think executor It's also a closure .- When designing a sub function , Extend for attributes .