手寫Axios(上)

閱讀建議

若是你對XMLHttpRequest的使用不熟悉,建議先在MDN上先行學習。ios

項目源碼已經上傳到github,並已添加註釋,您可直接查看源碼學習。git

文章已經同步到個人技術博客,歡迎交流。github

先來看axios的使用方式

axios({
  method: 'post',
  url: '/url',
  data: {
    a: 1,
    b: 2
  }
}).then((res) => {
  console.log(res)
})
複製代碼

axios核心

XMLHttpRequest:具體使用參見XMLHttpRequesttypescript

// xhr.js
const request = new XMLHttpRequest()
request.open(method.toUpperCase(), url, true)
request.onreadystatechange = function(){
  // 監聽xhr狀態改變
}
request.send(data)
複製代碼

數據處理

處理url

  1. 從config中獲取到url和params
  2. 若是沒有params選項,直接返回url
  3. 若是包含params,對params的key作遍歷。若是key爲空,忽略該params,若是key不爲空,針對value的不一樣類型作對應處理。具體代碼以下:
export function buildUrl(url: string, params: any): string {
  if (!params) return url;

  const parts: string[] = [];
  Object.keys(params).forEach((key) => {
    const val = params[key];
    if (val === null || typeof val === 'undefined') {
      return ''
    }
    let values = [];
    if (Array.isArray(val)) {
      values = val;
      key += '[]'
    } else {
      values = [val]
    }
    values.forEach((val) => {
      if (isDate(val)) {
        val = val.toISOString()
      } else if (isPlainObject(val)) {
        val = JSON.stringify(val)
      }
      parts.push(`${encode(key)}=${encode(val)}`)
    })
  })

  let serializedParams = parts.join('&');
  if (serializedParams) {
    const markIndex = url.indexOf('#')
    if (markIndex !== -1) {
      url = url.slice(0, markIndex)
    }
    url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams
  }
  return url
}
複製代碼

處理獲取到的data信息

處理data信息比較簡單,直接上代碼:json

export function transformRequest(data: any): any {
  if (isPlainObject(data)) {
    return JSON.stringify(data)
  }
  return data
}
複製代碼

處理頭部信息

  1. 考慮兼容Content-Type大小寫不一樣的狀況,利用normalizeHeaderName函數進行規範化
  2. 若是data是對象,而且不存在Content-Type,給其配置默認值爲'application/json;charset=utf-8',具體代碼以下:
function normalizeHeaderName(headers: any, normalizedName: string): void {
  if (!headers) return
  Object.keys(headers).forEach(name => {
    if (name !== normalizedName && name.toUpperCase() === normalizedName.toUpperCase()) {
      headers[normalizedName] = headers[name]
      delete headers[name]
    }
  })
}

export function processHeaders(headers: any, data: any): any {
  normalizeHeaderName(headers, 'Content-Type')
  if (isPlainObject(data)) {
    if (headers && !headers['Content-Type']) {
      headers['Content-Type'] = 'application/json;charset=utf-8'
    }
  }
  return headers
}
複製代碼

處理返回信息

export function transformResponse(data: any): any {
  if (typeof data === 'string') {
    try {
      data = JSON.parse(data)
    } catch (e) {
      // do nothing
    }
  }
  return data
}
複製代碼

Promise化

  1. 處理xhr.js,把xhr核心包含在promise裏面
  2. 當觸發onreadystatechange事件的時候,格式化響應數據,並對狀態進行判斷,分別觸發 resolve/reject事件
相關文章
相關標籤/搜索