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

axios?攔截器管理類(lèi)鏈?zhǔn)秸{(diào)用手寫(xiě)實(shí)現(xiàn)及原理剖析

 更新時(shí)間:2022年08月26日 17:09:54   作者:小p  
這篇文章主要為大家介紹了axios?攔截器管理類(lèi)鏈?zhǔn)秸{(diào)用手寫(xiě)實(shí)現(xiàn)及原理剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

axios庫(kù)的攔截器使用

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

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

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

并且我們是可以添加多個(gè)攔截器的,攔截器的執(zhí)行順序是鏈?zhǔn)揭来螆?zhí)行的方式。對(duì)于 request 攔截器,后添加的攔截器會(huì)在請(qǐng)求前的過(guò)程中先執(zhí)行;對(duì)于 response 攔截器,先添加的攔截器會(huì)在響應(yīng)后先執(zhí)行。

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

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

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

整體設(shè)計(jì)

我們先用一張圖來(lái)展示一下攔截器工作流程:

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

在這個(gè) Promise 鏈的執(zhí)行過(guò)程中,請(qǐng)求攔截器 resolve 函數(shù)處理的是 config 對(duì)象,而相應(yīng)攔截器 resolve 函數(shù)處理的是 response 對(duì)象。

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

攔截器管理類(lèi)實(shí)現(xiàn)

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

use 方法支持 2 個(gè)參數(shù),第一個(gè)是 resolve 函數(shù),第二個(gè)是 reject 函數(shù),對(duì)于 resolve 函數(shù)的參數(shù),請(qǐng)求攔截器是 AxiosRequestConfig 類(lèi)型的,而響應(yīng)攔截器是 AxiosResponse 類(lèi)型的;而對(duì)于 reject 函數(shù)的參數(shù)類(lèi)型則是 any 類(lèi)型的。

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

接口定義

這里我們定義了 AxiosInterceptorManager 泛型接口,因?yàn)閷?duì)于 resolve 函數(shù)的參數(shù),請(qǐng)求攔截器和響應(yīng)攔截器是不同的。

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
}

代碼實(shí)現(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
  }
  // 遍歷用戶(hù)寫(xiě)的攔截器,并執(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
    }
  }
}

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

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

鏈?zhǔn)秸{(diào)用實(shí)現(xiàn)

當(dāng)我們實(shí)現(xiàn)好攔截器管理類(lèi),接下來(lái)就是在 Axios 中定義一個(gè) interceptors 屬性,它的類(lèi)型如下:

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 類(lèi)型擁有 2 個(gè)屬性,一個(gè)請(qǐng)求攔截器管理類(lèi)實(shí)例,一個(gè)是響應(yīng)攔截器管理類(lèi)實(shí)例。我們?cè)趯?shí)例化 Axios 類(lèi)的時(shí)候,在它的構(gòu)造器去初始化這個(gè) interceptors 實(shí)例屬性。

接下來(lái),我們修改 request 方法的邏輯,添加攔截器鏈?zhǔn)秸{(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
  }
  // 定義一個(gè)數(shù)組,這個(gè)數(shù)組就是要執(zhí)行的任務(wù)鏈,默認(rèn)有一個(gè)真正發(fā)送請(qǐng)求的任務(wù)
  const chain: PromiseChain[] = [{
    resolved: dispatchRequest,
    rejected: undefined
  }]
  // 把用戶(hù)定義的請(qǐng)求攔截器存放到任務(wù)鏈中,請(qǐng)求攔截器最后注冊(cè)的最先執(zhí)行,所以使用unshift方法
  this.interceptors.request.forEach(interceptor => {
    chain.unshift(interceptor)
  })
  // 把響應(yīng)攔截器存放到任務(wù)鏈中
  this.interceptors.response.forEach(interceptor => {
    chain.push(interceptor)
  })
  // 利用config初始化一個(gè)promise
  let promise = Promise.resolve(config)
  // 遍歷任務(wù)鏈
  while (chain.length) {
    // 取出任務(wù)鏈的首個(gè)任務(wù)
    const { resolved, rejected } = chain.shift()!
    // resolved的執(zhí)行時(shí)機(jī)是就是上一個(gè)promise執(zhí)行resolve()的時(shí)候,這樣就形成了鏈?zhǔn)秸{(diào)用
    promise = promise.then(resolved, rejected)
  }
  return promise
}

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

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

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

以上就是axios 攔截器管理類(lèi)鏈?zhǔn)秸{(diào)用手寫(xiě)實(shí)現(xiàn)及原理剖析的詳細(xì)內(nèi)容,更多關(guān)于axios 攔截器管理類(lèi)鏈?zhǔn)秸{(diào)用的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論