為了方便運用,axios對象既能做對象運用,又能做函數運用.
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
這一點axios是怎樣做到的,能夠看到instance實際上是一個綁定this的函數,挪用axios就是挪用context.request
function createInstance(){
// 能當作函數運用的隱秘
var instance = bind(Axios.prototype.request, context);
// 能當作對象運用的隱秘
utils.extend(instance, Axios.prototype, context);
// 要拿到組織函數繼續的屬性
utils.extend(instance, context);
return instance
}
var axios = createInstance(defaults);
接下來我們看一下request要領,一切http要求的發送都邑挪用Axios.prototype.request
,這個函數能夠認為是全部axios的骨架,異常重要。
Axios.prototype.request = function request(config) {
// 每一個要求都邑從新合成一個config,所以經由過程操縱config對象,你能夠標識要求,做某些操縱,事實上每一個axios的攔截器都能拿到config對象
config = utils.merge(defaults, this.defaults, { method: 'get' }, config);
// 掛載攔截器的重要邏輯
var chain = [dispatchRequest, undefined];
var promise = Promise.resolve(config);
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
chain.unshift(interceptor.fulfilled, interceptor.rejected);
});
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
chain.push(interceptor.fulfilled, interceptor.rejected);
});
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
return promise;
}
從攔截器中的重要邏輯,我們能夠獲得以下幾點:
- 發送要求的全部實行遞次是,requestInterceptors ——》dispatchRequest ——》responseInterceptors
- 攔截器最初吸收的對象是config,axios運用中也劃定,要求的攔截器必須要返回config,這也是每一個要求攔截器的函數參數是config的緣由
- 攔截器的實行遞次與
interceptors.request.use(function () {/*...*/})
實行的遞次有關,即先use
的要求攔截器會先實行。 - 假如攔截器中的函數時async函數,會壅塞全部攔截器鏈的實行,而transformData不會,所以假如須要對要求的數據做異步處置懲罰的話,要在攔截器中完成。
看一下,差別的http method是怎樣復用request要領的
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
/*eslint func-names:0*/
Axios.prototype[method] = function(url, config) {
return this.request(utils.merge(config || {}, {
method: method,
url: url
}));
};
});
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
/*eslint func-names:0*/
Axios.prototype[method] = function(url, data, config) {
return this.request(utils.merge(config || {}, {
method: method,
url: url,
data: data
}));
};
});
接下來我們看dispatchRequest的中心邏輯:
// 處置懲罰config...
var adapter = config.adapter || defaults.adapter;
return adapter(config).then(function onAdapterResolution(response) {
throwIfCancellationRequested(config);
// Transform response data
response.data = transformData(
response.data,
response.headers,
config.transformResponse
);
return response;
}, function onAdapterRejection(reason) {
if (!isCancel(reason)) {
throwIfCancellationRequested(config);
// Transform response data
if (reason && reason.response) {
reason.response.data = transformData(
reason.response.data,
reason.response.headers,
config.transformResponse
);
}
}
return Promise.reject(reason);
});
能夠看到dispatchRequest的中心邏輯大概有三步
- 處置懲罰config
- 運用adapter發送要求,axios默許內置兩個adapter,一個是擔任在brower發送要求的,一個是擔任在node端發送要求,能夠在根文件的defaults下看到
- 組織相應數據
所以經由過程dispatchRequest要領的瀏覽,我們能夠獲得以下啟發:
- adapter是能夠替代的,所以假如你以為你的xhr或http的邏輯更適合營業的須要,完全能夠替代掉,你也完全能夠開闢出第三種adapter以處置懲罰特定狀況,比方開闢一個處置懲罰緩存的adapter,事實上我如今的項目就是如許做的。
- 相應的攔截器吸收到的是response對象
至此,我們已把axios的中心邏輯瀏覽終了,從中我們也能夠看到axios的易用性和可拓展性異常強。
尤其是可拓展性,發送要求到吸收相應的過程當中的一切部份險些都是可拓展的,尤其是config,adapter,interceptor留下了許多設想的空間。