溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

axios攔截器管理類鏈式調(diào)用怎么實現(xiàn)

發(fā)布時間:2022-08-27 11:35:04 來源:億速云 閱讀:238 作者:iii 欄目:開發(fā)技術

今天小編給大家分享一下axios攔截器管理類鏈式調(diào)用怎么實現(xiàn)的相關知識點,內(nèi)容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

    axios庫的攔截器使用

    我們知道axios庫的攔截器的使用方式如下:

    // 添加一個請求攔截器
    axios.interceptors.request.use(function (config) {
      // 在發(fā)送請求之前可以做一些事情
      return config;
    }, function (error) {
      // 處理請求錯誤
      return Promise.reject(error);
    });
    // 添加一個響應攔截器
    axios.interceptors.response.use(function (response) {
      // 處理響應數(shù)據(jù)
      return response;
    }, function (error) {
      // 處理響應錯誤
      return Promise.reject(error);
    });

    在 axios 對象上有一個 interceptors 對象屬性,該屬性又有 request 和 response 2 個屬性,它們都有一個 use 方法,use 方法支持 2 個參數(shù),第一個參數(shù)類似 Promise.then 的 resolve 函數(shù),第二個參數(shù)類似 Promise.then 的 reject 函數(shù)。我們可以在 resolve 函數(shù)和 reject 函數(shù)中執(zhí)行同步代碼或者是異步代碼邏輯。

    并且我們是可以添加多個攔截器的,攔截器的執(zhí)行順序是鏈式依次執(zhí)行的方式。對于 request 攔截器,后添加的攔截器會在請求前的過程中先執(zhí)行;對于 response 攔截器,先添加的攔截器會在響應后先執(zhí)行。

    axios.interceptors.request.use(config => {
      config.headers.test += '1'
      return config
    })
    axios.interceptors.request.use(config => {
      config.headers.test += '2'
      return config
    })

    此外,我們也可以支持刪除某個攔截器,如下:

    const myInterceptor = axios.interceptors.request.use(function () {/*...*/})
    axios.interceptors.request.eject(myInterceptor)

    整體設計

    我們先用一張圖來展示一下攔截器工作流程:

    axios攔截器管理類鏈式調(diào)用怎么實現(xiàn)

    整個過程是一個鏈式調(diào)用的方式,并且每個攔截器都可以支持同步和異步處理,我們自然而然地就聯(lián)想到使用 Promise 鏈的方式來實現(xiàn)整個調(diào)用過程。

    在這個 Promise 鏈的執(zhí)行過程中,請求攔截器 resolve 函數(shù)處理的是 config 對象,而相應攔截器 resolve 函數(shù)處理的是 response 對象。

    在了解了攔截器工作流程后,我們先要創(chuàng)建一個攔截器管理類,允許我們?nèi)ヌ砑?刪除和遍歷攔截器。

    攔截器管理類實現(xiàn)

    根據(jù)需求,axios 擁有一個 interceptors 對象屬性,該屬性又有 request 和 response 2 個屬性,它們對外提供一個 use 方法來添加攔截器,我們可以把這倆屬性看做是一個攔截器管理對象。

    use 方法支持 2 個參數(shù),第一個是 resolve 函數(shù),第二個是 reject 函數(shù),對于 resolve 函數(shù)的參數(shù),請求攔截器是 AxiosRequestConfig 類型的,而響應攔截器是 AxiosResponse 類型的;而對于 reject 函數(shù)的參數(shù)類型則是 any 類型的。

    根據(jù)上述分析,我們先來定義一下攔截器管理對象對外的接口。

    接口定義

    這里我們定義了 AxiosInterceptorManager 泛型接口,因為對于 resolve 函數(shù)的參數(shù),請求攔截器和響應攔截器是不同的。

    export interface AxiosInterceptorManager<T> {
      use(resolved: ResolvedFn<T>, rejected?: RejectedFn): number
      eject(id: number): void
    }
    export interface ResolvedFn<T=any> {
      (val: T): T | Promise<T>
    }
    export interface RejectedFn {
      (error: any): any
    }

    代碼實現(xiàn)

    import { ResolvedFn, RejectedFn } from '../types'
    interface Interceptor<T> {
      resolved: ResolvedFn<T>
      rejected?: RejectedFn
    }
    export default class InterceptorManager<T> {
      private interceptors: Array<Interceptor<T> | null>
      constructor() {
        // 攔截器數(shù)組
        this.interceptors = []
      }
      // 收集攔截器  
      use(resolved: ResolvedFn<T>, rejected?: RejectedFn): number {
        this.interceptors.push({
          resolved,
          rejected
        })
        return this.interceptors.length - 1
      }
      // 遍歷用戶寫的攔截器,并執(zhí)行fn函數(shù)把攔截器作為參數(shù)傳入
      forEach(fn: (interceptor: Interceptor<T>) => void): void {
        this.interceptors.forEach(interceptor => {
          if (interceptor !== null) {
            fn(interceptor)
          }
        })
      }
      eject(id: number): void {
        if (this.interceptors[id]) {
          // 置為null,不能直接刪除
          this.interceptors[id] = null
        }
      }
    }

    我們定義了一個 InterceptorManager 泛型類,內(nèi)部維護了一個私有屬性 interceptors,它是一個數(shù)組,用來存儲攔截器。該類還對外提供了 3 個方法,其中 use 接口就是添加攔截器到 interceptors 中,并返回一個 id 用于刪除;

    forEach 接口就是遍歷 interceptors 用的,它支持傳入一個函數(shù),遍歷過程中會調(diào)用該函數(shù),并把每一個 interceptor 作為該函數(shù)的參數(shù)傳入;eject 就是刪除一個攔截器,通過傳入攔截器的 id 刪除。

    鏈式調(diào)用實現(xiàn)

    當我們實現(xiàn)好攔截器管理類,接下來就是在 Axios 中定義一個 interceptors 屬性,它的類型如下:

    interface Interceptors {
      request: InterceptorManager<AxiosRequestConfig>
      response: InterceptorManager<AxiosResponse>
    }
    export default class Axios {
      interceptors: Interceptors
      constructor() {
        this.interceptors = {
          request: new InterceptorManager<AxiosRequestConfig>(),
          response: new InterceptorManager<AxiosResponse>()
        }
      }
    }

    Interceptors 類型擁有 2 個屬性,一個請求攔截器管理類實例,一個是響應攔截器管理類實例。我們在實例化 Axios 類的時候,在它的構造器去初始化這個 interceptors 實例屬性。

    接下來,我們修改 request 方法的邏輯,添加攔截器鏈式調(diào)用的邏輯:

    interface PromiseChain {
      resolved: ResolvedFn | ((config: AxiosRequestConfig) => AxiosPromise)
      rejected?: RejectedFn
    }
    request(url: any, config?: any): AxiosPromise {
      if (typeof url === 'string') {
        if (!config) {
          config = {}
        }
        config.url = url
      } else {
        config = url
      }
      // 定義一個數(shù)組,這個數(shù)組就是要執(zhí)行的任務鏈,默認有一個真正發(fā)送請求的任務
      const chain: PromiseChain[] = [{
        resolved: dispatchRequest,
        rejected: undefined
      }]
      // 把用戶定義的請求攔截器存放到任務鏈中,請求攔截器最后注冊的最先執(zhí)行,所以使用unshift方法
      this.interceptors.request.forEach(interceptor => {
        chain.unshift(interceptor)
      })
      // 把響應攔截器存放到任務鏈中
      this.interceptors.response.forEach(interceptor => {
        chain.push(interceptor)
      })
      // 利用config初始化一個promise
      let promise = Promise.resolve(config)
      // 遍歷任務鏈
      while (chain.length) {
        // 取出任務鏈的首個任務
        const { resolved, rejected } = chain.shift()!
        // resolved的執(zhí)行時機是就是上一個promise執(zhí)行resolve()的時候,這樣就形成了鏈式調(diào)用
        promise = promise.then(resolved, rejected)
      }
      return promise
    }

    首先,構造一個 PromiseChain 類型的數(shù)組 chain,并把 dispatchRequest 函數(shù)賦值給 resolved 屬性;接著先遍歷請求攔截器插入到 chain 的前面;然后再遍歷響應攔截器插入到 chain 后面。

    接下來定義一個已經(jīng) resolve 的 promise,循環(huán)這個 chain,拿到每個攔截器對象,把它們的 resolved 函數(shù)和 rejected 函數(shù)添加到 promise.then 的參數(shù)中,這樣就相當于通過 Promise 的鏈式調(diào)用方式,實現(xiàn)了攔截器一層層的鏈式調(diào)用的效果。

    注意我們攔截器的執(zhí)行順序,對于請求攔截器,先執(zhí)行后添加的,再執(zhí)行先添加的;而對于響應攔截器,先執(zhí)行先添加的,后執(zhí)行后添加的。

    以上就是“axios攔截器管理類鏈式調(diào)用怎么實現(xiàn)”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業(yè)資訊頻道。

    向AI問一下細節(jié)

    免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

    AI