欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解axios跨端架構(gòu)是如何實(shí)現(xiàn)的

 更新時(shí)間:2024年04月28日 11:56:49   作者:zhangbao90s  
我們都知道,axios 是是一個(gè)跨平臺(tái)請(qǐng)求方案,在瀏覽器端采用 XMLHttpRequest API 進(jìn)行封裝,而在 Node.js 端則采用 http/https 模塊進(jìn)行封裝,那么本文,我們將來(lái)探討這個(gè)話題:axios 的跨端架構(gòu)是如何實(shí)現(xiàn)的,需要的朋友可以參考下

介紹

我們都知道,axios 是是一個(gè)跨平臺(tái)請(qǐng)求方案,在瀏覽器端采用 XMLHttpRequest API 進(jìn)行封裝,而在 Node.js 端則采用 http/https 模塊進(jìn)行封裝。axios 內(nèi)部采用適配器模式將二者合二為一,在隱藏了底層的實(shí)現(xiàn)的同時(shí),又對(duì)外開(kāi)放了一套統(tǒng)一的開(kāi)放接口。

那么本文,我們將來(lái)探討這個(gè)話題:axios 的跨端架構(gòu)是如何實(shí)現(xiàn)的?

從 axios 發(fā)送請(qǐng)求說(shuō)起

我們先來(lái)看看 axios 是如何發(fā)送請(qǐng)求的。

// 發(fā)送一個(gè) GET 請(qǐng)求
axios({ 
  method: 'get',
  url: 'https://jsonplaceholder.typicode.com/comments'
  params: { postId: 1 }
}) 

// 發(fā)送一個(gè) POST 請(qǐng)求
axios({
  method: 'post'
  url: 'https://jsonplaceholder.typicode.com/posts',
  data: {
    title: 'foo',
    body: 'bar',
    userId: 1,
  }
})

dispatchRequest() 方法

當(dāng)使用 axios 請(qǐng)求時(shí),實(shí)際上內(nèi)部是由 Axios 實(shí)例的 .request() 方法處理的。

// /v1.6.8/lib/core/Axios.js#L38
async request(configOrUrl, config) {
    try {
      return await this._request(configOrUrl, config);
    } catch (err) {}
}

而 ._request() 方法內(nèi)部會(huì)先將 configOrUrl, config 2 個(gè)參數(shù)處理成 config 參數(shù)。

// /v1.6.8/lib/core/Axios.js#L62
_request(configOrUrl, config) {
    if (typeof configOrUrl === 'string') {
      config = config || {};
      config.url = configOrUrl;
    } else {
      config = configOrUrl || {};
    }

    // ...
}

這里是為了同時(shí)兼容下面 2 種調(diào)用方法。

// 調(diào)用方式一
axios('https://jsonplaceholder.typicode.com/posts/1')
// 調(diào)用方式二
axios({
  method: 'get',
  url: 'https://jsonplaceholder.typicode.com/posts/1'
})

當(dāng)然,這不是重點(diǎn)。在 ._request() 方法內(nèi)部請(qǐng)求最終會(huì)交由 dispatchRequest() 處理。

// /v1.6.8/lib/core/Axios.js#L169-L173
try {
  promise = dispatchRequest.call(this, newConfig);
} catch (error) {
  return Promise.reject(error);
}

dispatchRequest() 是實(shí)際調(diào)用請(qǐng)求的地方,而實(shí)際調(diào)用是采用 XMLHttpRequest API(瀏覽器)還是http/https 模塊(Node.js),則需要進(jìn)一步查看。

// /v1.6.8/lib/core/dispatchRequest.js#L34
export default function dispatchRequest(config) { /* ... */ }

dispatchRequest() 接收的是上一步合并之后的 config 參數(shù),有了這個(gè)參數(shù)我們就可以發(fā)送請(qǐng)求了。

跨端適配實(shí)現(xiàn)

// /v1.6.8/lib/core/dispatchRequest.js#L49
const adapter = adapters.getAdapter(config.adapter || defaults.adapter);

這里就是我們所說(shuō)的 axios 內(nèi)部所使用的適配器模式了。

axios 支持從外出傳入 adapter 參數(shù)支持自定義請(qǐng)求能力的實(shí)現(xiàn),不過(guò)很少使用。大部分請(qǐng)求下,我們都是使用內(nèi)置的適配器實(shí)現(xiàn)。

defaults.adapter

defaults.adapter 的值如下:

// /v1.6.8/lib/defaults/index.js#L40
adapter: ['xhr', 'http'],

adapters.getAdapter(['xhr', 'http']) 又是在做什么事情呢?

適配器實(shí)現(xiàn)

首先,adapters 位于 lib/adapters/adapters.js。

所屬的目錄結(jié)構(gòu)如下:

可以看到針對(duì)瀏覽器和 Node.js 2 個(gè)環(huán)境的適配支持:http.js、xhr.js。

adapters 的實(shí)現(xiàn)如下。

首先,將內(nèi)置的 2 個(gè)適配文件引入。

// /v1.6.8/lib/adapters/adapters.js#L2-L9
import httpAdapter from './http.js';
import xhrAdapter from './xhr.js';

const knownAdapters = {
  http: httpAdapter,
  xhr: xhrAdapter
}

knownAdapters 的屬性名正好是和 defaults.adapter 的值 ['xhr', 'http'] 是一一對(duì)應(yīng)的。

而 adapters.getAdapter(['xhr', 'http']) 的實(shí)現(xiàn)是這樣的:

// /v1.6.8/lib/adapters/adapters.js#L27-L75
export default {
  getAdapter: (adapters) => {
    // 1)
    adapters = Array.isArray(adapters) ? adapters : [adapters];

    let nameOrAdapter;
    let adapter;
    
    // 2)
    for (let i = 0; i < adapters.length; i++) {
      nameOrAdapter = adapters[i];
      adapter = nameOrAdapter;
      
      // 3)
      if (!isResolvedHandle(nameOrAdapter)) {
        adapter = knownAdapters[String(nameOrAdapter).toLowerCase()];
      }

      if (adapter) {
        break;
      }
    }

    // 4)
    if (!adapter) {
      throw new AxiosError(
        `There is no suitable adapter to dispatch the request `,
        'ERR_NOT_SUPPORT'
      );
    }

    return adapter;
  }
}

內(nèi)容比較長(zhǎng),我們會(huì)按照代碼標(biāo)準(zhǔn)的序號(hào)分 4 個(gè)部分來(lái)講。

1)、這里是為了兼容調(diào)用 axios() 時(shí)傳入 adapter 參數(shù)的情況。

// `adapter` allows custom handling of requests which makes testing easier.
// Return a promise and supply a valid response (see lib/adapters/README.md).
adapter: function (config) {
  /* ... */
},

因?yàn)榻酉聛?lái) adapters 是作為數(shù)組處理,所以這種場(chǎng)景下,我們將 adapter 封裝成數(shù)組 [adapters]

// /v1.6.8/lib/adapters/adapters.js#L28
adapters = Array.isArray(adapters) ? adapters : [adapters];

2)、接下來(lái),就是遍歷 adapters 找到要用的那個(gè)適配器。

到目前為止,adapters[i](也就是下面的 nameOrAdapter)既可能是字符串('xhr'、'http'),也可能是函數(shù)(function (config) {})。

// /v1.6.8/lib/adapters/adapters.js#L37
let nameOrAdapter = adapters[i];
adapter = nameOrAdapter;

3)、那么,我們還要檢查 nameOrAdapter 的類型。

// /v1.6.8/lib/adapters/adapters.js#L42-L48
if (!isResolvedHandle(nameOrAdapter)) {
  adapter = knownAdapters[(id = String(nameOrAdapter)).toLowerCase()];
}

isResolvedHandle() 是一個(gè)工具函數(shù),其目的是為了判斷是否要從 knownAdapters 獲取適配器。

// /v1.6.8/lib/adapters/adapters.js#L24
const isResolvedHandle = (adapter) => typeof adapter === 'function' || adapter === null || adapter === false;

簡(jiǎn)單理解,只有 adapter 是字符串的情況('xhr''http'),isResolvedHandle(nameOrAdapter) 才返回 false,才從 knownAdapters 獲得適配器。

typeof adapter === 'function' || adapter === null 這個(gè)判斷條件我們?nèi)菀桌斫?,這是為了排除自定義 adapter 參數(shù)(傳入函數(shù)或 null)的情況。

而 adapter === false 又是對(duì)應(yīng)什么情況呢?

那是因?yàn)槲覀兊拇a只可能是在瀏覽器或 Node.js 環(huán)境下運(yùn)行。這個(gè)時(shí)候 httpAdapter 和 xhrAdapter 具體返回是有差異的。

// /v1.6.8/lib/adapters/xhr.js#L48
const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined';
export default isXHRAdapterSupported && function (config) {/* ...*/}

// /v1.6.8/lib/adapters/http.js#L160
const isHttpAdapterSupported = typeof process !== 'undefined' && utils.kindOf(process) === 'process';
export default isHttpAdapterSupported && function httpAdapter(config) {/* ... */}

也就是說(shuō):在瀏覽器環(huán)境 httpAdapter 返回 false,xhrAdapter 返回函數(shù);在 Node.js 環(huán)境 xhrAdapter 返回 false,httpAdapter 返回函數(shù)。

因此,一旦 isResolvedHandle() 邏輯執(zhí)行完成后。

if (!isResolvedHandle(nameOrAdapter)) {/* ... */}

會(huì)檢查 adapter 變量的值,一旦有值(非 false)就說(shuō)明找到適配器了,結(jié)束遍歷。

if (adapter) {
  break;
}

4)、最終在返回適配器前做空檢查

// 4)
if (!adapter) {
  throw new AxiosError(
    `There is no suitable adapter to dispatch the request `,
    'ERR_NOT_SUPPORT'
  );
}

return adapter;

如此,就完成了跨端架構(gòu)的實(shí)現(xiàn)。

總結(jié)

本文我們講述了 axios 的跨端架構(gòu)原理。axios 內(nèi)部實(shí)際發(fā)出請(qǐng)求是通過(guò) dispatchRequest() 方法處理的,再往里看則是通過(guò)適配器模式取得適應(yīng)于當(dāng)前環(huán)境的適配器函數(shù)。

axios 內(nèi)置了 2 個(gè)適配器支持:httpAdapter 和 xhrAdapter。httpAdapter 是 Node.js 環(huán)境實(shí)現(xiàn),通過(guò) http/https 模塊;xhrAdapter 這是瀏覽器環(huán)境實(shí)現(xiàn),通過(guò) XMLHttpRequest API 實(shí)現(xiàn)。Node.js 環(huán)境 xhrAdapter 返回 false,瀏覽器環(huán)境 httpAdapter 返回 false——這樣總是能返回正確的適配器。

以上就是詳解axios跨端架構(gòu)是如何實(shí)現(xiàn)的的詳細(xì)內(nèi)容,更多關(guān)于axios跨端架構(gòu)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • window.event.srcElement 得到事件源對(duì)象

    window.event.srcElement 得到事件源對(duì)象

    window.event.srcElement 得到事件源對(duì)象代碼,大家可以參考腳本之家以前發(fā)的代碼,多瀏覽兼容的。
    2009-05-05
  • JavaScript 對(duì)象深入學(xué)習(xí)總結(jié)(經(jīng)典)

    JavaScript 對(duì)象深入學(xué)習(xí)總結(jié)(經(jīng)典)

    JavaScript中,除了五種原始類型(即數(shù)字,字符串,布爾值,null,undefined)之外的都是對(duì)象了,所以,不把對(duì)象學(xué)明白怎么繼續(xù)往下學(xué)習(xí)呢?本篇文章給大家分享javascript對(duì)象深入學(xué)習(xí)總結(jié),小伙伴們跟著小編一起深入學(xué)習(xí)吧
    2015-09-09
  • Bootstrap3多級(jí)下拉菜單

    Bootstrap3多級(jí)下拉菜單

    這篇文章主要為大家詳細(xì)介紹了Bootstrap3多級(jí)下拉菜單的相關(guān)資料,需引用bootstrap.min.css和bootstrap.min.css.js,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-02-02
  • js實(shí)現(xiàn)圖片查看器

    js實(shí)現(xiàn)圖片查看器

    這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)圖片查看器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • JS實(shí)現(xiàn)的自定義map方法示例

    JS實(shí)現(xiàn)的自定義map方法示例

    這篇文章主要介紹了JS實(shí)現(xiàn)的自定義map方法,結(jié)合實(shí)例形式分析了javascript自定義map相關(guān)的json數(shù)組定義、遍歷、添加、刪除、讀取等相關(guān)操作技巧,需要的朋友可以參考下
    2019-05-05
  • 關(guān)于JS中的作用域中的問(wèn)題思考分享

    關(guān)于JS中的作用域中的問(wèn)題思考分享

    這篇文章主要介紹了關(guān)于JS中的作用域中的問(wèn)題思考分享,scope和?closure是?javascript中兩個(gè)非常關(guān)鍵的概念,前者JS用多了還比較好理解而且容易體會(huì)到,而?closure就不一樣了。這玩意是真的很容易迷糊,需要的朋友可以參考下
    2022-04-04
  • JavaScript回調(diào)函數(shù)callback用法解析

    JavaScript回調(diào)函數(shù)callback用法解析

    這篇文章主要介紹了JavaScript回調(diào)函數(shù)callback用法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • JavaScript實(shí)現(xiàn)多文件拖動(dòng)上傳功能

    JavaScript實(shí)現(xiàn)多文件拖動(dòng)上傳功能

    這篇文章主要為大家詳細(xì)介紹了如何使用JavaScript實(shí)現(xiàn)多文件拖動(dòng)上傳功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-04-04
  • js編寫(xiě)的treeview使用方法

    js編寫(xiě)的treeview使用方法

    這篇文章主要為大家詳細(xì)介紹了js編寫(xiě)的treeview使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • 前端打斷點(diǎn)debugger使用流程詳細(xì)教程

    前端打斷點(diǎn)debugger使用流程詳細(xì)教程

    這篇文章主要介紹了前端打斷點(diǎn)debugger使用的相關(guān)資料,包括如何設(shè)置斷點(diǎn)、如何使用調(diào)試按鈕以及如何查看變量,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2024-12-12

最新評(píng)論