日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[js] axios为什么可以使用对象和函数两种方式调用?是如何实现的?

發布時間:2023/12/9 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [js] axios为什么可以使用对象和函数两种方式调用?是如何实现的? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

[js] axios為什么可以使用對象和函數兩種方式調用?是如何實現的?

axios 源碼 初始化
看源碼第一步,先看package.json。一般都會申明 main 主入口文件。
// package.json
{
“name”: “axios”,
“version”: “0.19.0”,
“description”: “Promise based HTTP client for the browser and node.js”,
“main”: “index.js”,
// …
}
復制代碼
主入口文件
// index.js
module.exports = require(’./lib/axios’);
復制代碼
4.1 lib/axios.js主文件
axios.js文件 代碼相對比較多。分為三部分展開敘述。

第一部分:引入一些工具函數utils、Axios構造函數、默認配置defaults等。
第二部分:是生成實例對象 axios、axios.Axios、axios.create等。
第三部分取消相關API實現,還有all、spread、導出等實現。

4.1.1 第一部分
引入一些工具函數utils、Axios構造函數、默認配置defaults等。
// 第一部分:
// lib/axios
// 嚴格模式
‘use strict’;
// 引入 utils 對象,有很多工具方法。
var utils = require(’./utils’);
// 引入 bind 方法
var bind = require(’./helpers/bind’);
// 核心構造函數 Axios
var Axios = require(’./core/Axios’);
// 合并配置方法
var mergeConfig = require(’./core/mergeConfig’);
// 引入默認配置
var defaults = require(’./defaults’);
復制代碼
4.1.2 第二部分
是生成實例對象 axios、axios.Axios、axios.create等。
/**

  • Create an instance of Axios
  • @param {Object} defaultConfig The default config for the instance
  • @return {Axios} A new instance of Axios
    */
    function createInstance(defaultConfig) {
    // new 一個 Axios 生成實例對象
    var context = new Axios(defaultConfig);
    // bind 返回一個新的 wrap 函數,
    // 也就是為什么調用 axios 是調用 Axios.prototype.request 函數的原因
    var instance = bind(Axios.prototype.request, context);
    // Copy axios.prototype to instance
    // 復制 Axios.prototype 到實例上。
    // 也就是為什么 有 axios.get 等別名方法,
    // 且調用的是 Axios.prototype.get 等別名方法。
    utils.extend(instance, Axios.prototype, context);
    // Copy context to instance
    // 復制 context 到 intance 實例
    // 也就是為什么默認配置 axios.defaults 和攔截器 axios.interceptors 可以使用的原因
    // 其實是new Axios().defaults 和 new Axios().interceptors
    utils.extend(instance, context);
    // 最后返回實例對象,以上代碼,在上文的圖中都有體現。這時可以仔細看下上圖。
    return instance;
    }

// Create the default instance to be exported
// 導出 創建默認實例
var axios = createInstance(defaults);
// Expose Axios class to allow class inheritance
// 暴露 Axios class 允許 class 繼承 也就是可以 new axios.Axios()
// 但 axios 文檔中 并沒有提到這個,我們平時也用得少。
axios.Axios = Axios;

// Factory for creating new instances
// 工廠模式 創建新的實例 用戶可以自定義一些參數
axios.create = function create(instanceConfig) {
return createInstance(mergeConfig(axios.defaults, instanceConfig));
};
復制代碼
這里簡述下工廠模式。axios.create,也就是用戶不需要知道內部是怎么實現的。
舉個生活的例子,我們買手機,不需要知道手機是怎么做的,就是工廠模式。
看完第二部分,里面涉及幾個工具函數,如bind、extend。接下來講述這幾個工具方法。
4.1.3 工具方法之 bind
axios/lib/helpers/bind.js
‘use strict’;
// 返回一個新的函數 wrap
module.exports = function bind(fn, thisArg) {
return function wrap() {
var args = new Array(arguments.length);
for (var i = 0; i < args.length; i++) {
args[i] = arguments[i];
}
// 把 argument 對象放在數組 args 里
return fn.apply(thisArg, args);
};
};
復制代碼
傳遞兩個參數函數和thisArg指向。
把參數arguments生成數組,最后調用返回參數結構。
其實現在 apply 支持 arguments這樣的類數組對象了,不需要手動轉數組。
那么為啥作者要轉數組,為了性能?當時不支持?抑或是作者不知道?這就不得而知了。有讀者知道歡迎評論區告訴筆者呀。
關于apply、call和bind等不是很熟悉的讀者,可以看筆者的另一個面試官問系列。
面試官問:能否模擬實現JS的bind方法
舉個例子
function fn(){
console.log.apply(console, arguments);
}
fn(1,2,3,4,5,6, ‘若川’);
// 1 2 3 4 5 6 ‘若川’
復制代碼
4.1.4 工具方法之 utils.extend
axios/lib/utils.js
function extend(a, b, thisArg) {
forEach(b, function assignValue(val, key) {
if (thisArg && typeof val === ‘function’) {
a[key] = bind(val, thisArg);
} else {
a[key] = val;
}
});
return a;
}
復制代碼
其實就是遍歷參數 b 對象,復制到 a 對象上,如果是函數就是則用 bind 調用。
4.1.5 工具方法之 utils.forEach
axios/lib/utils.js
遍歷數組和對象。設計模式稱之為迭代器模式。很多源碼都有類似這樣的遍歷函數。比如大家熟知的jQuery $.each。
/**

  • @param {Object|Array} obj The object to iterate
  • @param {Function} fn The callback to invoke for each item
    */
    function forEach(obj, fn) {
    // Don’t bother if no value provided
    // 判斷 null 和 undefined 直接返回
    if (obj === null || typeof obj === ‘undefined’) {
    return;
    }

// Force an array if not already something iterable
// 如果不是對象,放在數組里。
if (typeof obj !== ‘object’) {
/eslint no-param-reassign:0/
obj = [obj];
}

// 是數組 則用for 循環,調用 fn 函數。參數類似 Array.prototype.forEach 的前三個參數。
if (isArray(obj)) {
// Iterate over array values
for (var i = 0, l = obj.length; i < l; i++) {
fn.call(null, obj[i], i, obj);
}
} else {
// Iterate over object keys
// 用 for in 遍歷對象,但 for in 會遍歷原型鏈上可遍歷的屬性。
// 所以用 hasOwnProperty 來過濾自身屬性了。
// 其實也可以用Object.keys來遍歷,它不遍歷原型鏈上可遍歷的屬性。
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
fn.call(null, obj[key], key, obj);
}
}
}
}
復制代碼
如果對Object相關的API不熟悉,可以查看筆者之前寫過的一篇文章。JavaScript 對象所有API解析
4.1.6 第三部分
取消相關API實現,還有all、spread、導出等實現。
// Expose Cancel & CancelToken
// 導出 Cancel 和 CancelToken
axios.Cancel = require(’./cancel/Cancel’);
axios.CancelToken = require(’./cancel/CancelToken’);
axios.isCancel = require(’./cancel/isCancel’);

// Expose all/spread
// 導出 all 和 spread API
axios.all = function all(promises) {
return Promise.all(promises);
};
axios.spread = require(’./helpers/spread’);

module.exports = axios;

// Allow use of default import syntax in TypeScript
// 也就是可以以下方式引入
// import axios from ‘axios’;
module.exports.default = axios;
復制代碼
這里介紹下 spread,取消的API暫時不做分析,后文再詳細分析。
假設你有這樣的需求。
function f(x, y, z) {}
var args = [1, 2, 3];
f.apply(null, args);
復制代碼
那么可以用spread方法。用法:
axios.spread(function(x, y, z) {})([1, 2, 3]);
復制代碼
實現也比較簡單。源碼實現:
/**

  • @param {Function} callback
  • @returns {Function}
    */
    module.exports = function spread(callback) {
    return function wrap(arr) {
    return callback.apply(null, arr);
    };
    };
    復制代碼
    上文var context = new Axios(defaultConfig);,接下來介紹核心構造函數Axios。
    4.2 核心構造函數 Axios
    axios/lib/core/Axios.js
    構造函數Axios。
    function Axios(instanceConfig) {
    // 默認參數
    this.defaults = instanceConfig;
    // 攔截器 請求和響應攔截器
    this.interceptors = {
    request: new InterceptorManager(),
    response: new InterceptorManager()
    };
    }
    復制代碼
    Axios.prototype.request = function(config){
    // 省略,這個是核心方法,后文結合例子詳細描述
    // code …
    var promise = Promise.resolve(config);
    // code …
    return promise;
    }
    // 這是獲取 Uri 的函數,這里省略
    Axios.prototype.getUri = function(){}
    // 提供一些請求方法的別名
    // Provide aliases for supported request methods
    // 遍歷執行
    // 也就是為啥我們可以 axios.get 等別名的方式調用,而且調用的是 Axios.prototype.request 方法
    // 這個也在上面的 axios 結構圖上有所體現。
    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
}));
};
});

module.exports = Axios;
復制代碼
接下來看攔截器部分。
4.3 攔截器管理構造函數 InterceptorManager
請求前攔截,和請求后攔截。
在Axios.prototype.request函數里使用,具體怎么實現的攔截的,后文配合例子詳細講述。
axios github 倉庫 攔截器文檔
如何使用:
// Add a request interceptor
// 添加請求前攔截器
axios.interceptors.request.use(function (config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});

// Add a response interceptor
// 添加請求后攔截器
axios.interceptors.response.use(function (response) {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
return response;
}, function (error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error);
});
復制代碼
如果想把攔截器,可以用eject方法。
const myInterceptor = axios.interceptors.request.use(function () {/…/});
axios.interceptors.request.eject(myInterceptor);
復制代碼
攔截器也可以添加自定義的實例上。
const instance = axios.create();
instance.interceptors.request.use(function () {/…/});
復制代碼
源碼實現:
構造函數,handles 用于存儲攔截器函數。
function InterceptorManager() {
this.handlers = [];
}
復制代碼
接下來聲明了三個方法:使用、移除、遍歷。
4.3.1 InterceptorManager.prototype.use 使用
傳遞兩個函數作為參數,數組中的一項存儲的是{fulfilled: function(){}, rejected: function(){}}。返回數字 ID,用于移除攔截器。
/**

  • @param {Function} fulfilled The function to handle then for a Promise
  • @param {Function} rejected The function to handle reject for a Promise
  • @return {Number} 返回ID 是為了用 eject 移除
    /
    InterceptorManager.prototype.use = function use(fulfilled, rejected) {
    this.handlers.push({
    fulfilled: fulfilled,
    rejected: rejected
    });
    return this.handlers.length - 1;
    };
    復制代碼
    4.3.2 InterceptorManager.prototype.eject 移除
    根據 use 返回的 ID 移除 攔截器。
    /*
  • @param {Number} id The ID that was returned by use
    /
    InterceptorManager.prototype.eject = function eject(id) {
    if (this.handlers[id]) {
    this.handlers[id] = null;
    }
    };
    復制代碼
    有點類似定時器setTimeout 和 setInterval,返回值是id。用clearTimeout 和clearInterval來清除定時器。
    // 提一下 定時器回調函數是可以傳參的,返回值 timer 是數字
    var timer = setInterval((name) => {
    console.log(name);
    }, 1000, ‘若川’);
    console.log(timer); // 數字 ID
    // 在控制臺等會再輸入執行這句,定時器就被清除了
    clearInterval(timer);
    復制代碼
    4.3.3 InterceptorManager.prototype.forEach 遍歷
    遍歷執行所有攔截器,傳遞一個回調函數(每一個攔截器函數作為參數)調用,被移除的一項是null,所以不會執行,也就達到了移除的效果。
    /*
  • @param {Function} fn The function to call for each interceptor
    */
    InterceptorManager.prototype.forEach = function forEach(fn) {
    utils.forEach(this.handlers, function forEachHandler(h) {
    if (h !== null) {
    fn(h);
    }
    });
    };
    復制代碼
  • 實例結合
    上文敘述的調試時運行npm start 是用axios/sandbox/client.html路徑的文件作為示例的,讀者可以自行調試。
    以下是一段這個文件中的代碼。
    axios(options)
    .then(function (res) {
    response.innerHTML = JSON.stringify(res.data, null, 2);
    })
    .catch(function (res) {
    response.innerHTML = JSON.stringify(res.data, null, 2);
    });
  • 個人簡介

    我是歌謠,歡迎和大家一起交流前后端知識。放棄很容易,
    但堅持一定很酷。歡迎大家一起討論

    主目錄

    與歌謠一起通關前端面試題

    總結

    以上是生活随笔為你收集整理的[js] axios为什么可以使用对象和函数两种方式调用?是如何实现的?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。