Ajax和Axios实现

实现原生Ajax

简介

AJAX = 异步 JavaScript 和 XML。

AJAX 是一种用于创建快速动态网页的技术。

通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。

详细介绍请移步AJAX 简介 | 菜鸟教程

最简版本

function myAjax(method, url) {
  const xhr = new XMLHttpRequest()
  xhr.open(method, url)
  xhr.onreadystatechange = function () {
    if (xhr.readyState === 4) {
      if (xhr.status === 200 || xhr.status === 304) {
        console.log(xhr.responseText);
      } else {
        console.log(new Error(xhr.statusText));
      }
    }
  }
  xhr.send()
}

带promis版本

function myAjax(method, url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()
    xhr.open(method, url)
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status === 200 || xhr.status === 304) {
          resolve(xhr.responseText)
        } else {
          resolve(new Error(xhr.statusText))
        }
      }
    }
    xhr.send()
  })
}

实现Axios

在平时写项目中大部分都会用到axios,但是对axios的实现却没怎么了解过,今天趁着休息,用js实现axios

简介

Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js http 模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。

具体详细介绍请移步起步 | Axios中文文档 | Axios中文网

这里实现出几个主要的方法,包括post请求方法,create配置方法,以及拦截器的方法。

1.post方法

实现前先写一个类,在类的原型对象上进行方法的实现

function cAxios() {

}

实现时注意两点:

  • axios的post的方法返回的是一个promise对象
  • axios的post的方法的data参数是一个对象,而原生的XMLHttpRequest对象的send方法参数是string

所以需要在send方法里面把data参数转化为JSON格式的字符串

cAxios.prototype.post = function (method, url, data) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()
    xhr.open(method, url)
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status === 200 || xhr.status === 304) {
          resolve(xhr.responseText)
        } else {
          reject(new Error(reject.statusText))
        }
      }
    }
    xhr.send(JSON.stringify(data))
  })
}

get方法也是一样的,不再描述

2.create方法

axios.create(config)

  1. 根据指定配置创建一个新的 axios, 也就就每个新 axios 都有自己的配置(主要是请求头的配置)
  2. 新 axios 只是没有取消请求和批量发请求的方法, 其它所有语法都是一致的

这里的实现只是列举了headers和baseUrl这两个属性

cAxios.prototype.create = function (obj) {
  let axios = new cAxios()
  axios.headers = obj.headers;
  axios.baseUrl = obj.baseUrl;
  return axios
}

所以如果我们设置请求头以后,调用post方法需要带上这些参数,因此post方法需要修改

首先需要写一个方法来配置请求头

function setHeaders(xhr, headers){
  for(let key in headers) {
    xhr.setquestHeader(key, headers[key])
  }
}

在post方法中,在ajax发送请求之前调用即可

setHeaders(xhr, this.headers)

3.拦截器

axios的拦截器分为请求拦截器和响应拦截器

含义:在请求或响应被 then 或 catch 处理前拦截它们。

官网实例

// 添加请求拦截器
axios.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    return config;
  }, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  });

// 添加响应拦截器
axios.interceptors.response.use(function (response) {
    // 2xx 范围内的状态码都会触发该函数。
    // 对响应数据做点什么
    return response;
  }, function (error) {
    // 超出 2xx 范围的状态码都会触发该函数。
    // 对响应错误做点什么
    return Promise.reject(error);
  });

这里可以看到interceptors是一个对象,里面包含request和response属性

本文实现不考虑use

我们需要在类里面实现一下interceptors

 this.interceptors = {
   request(fn) {
     _this.saveReqFn.push(fn)
   },
   response(fn) {
     _this.saveResFn.push(fn)
   }
}

如果我们想在外边调用请求拦截器或者响应拦截器,需要传递一个回调函数作为拦截器的参数
所以在我们这里我们需要把这个回调函数保存下来(考虑到有多个拦截器,所以我们采用数组保存)。

同时我们也要写一个data用于存放请求时的数据(因为在请求拦截器的回调函数中,有一个config参数,它包含着请求的数据)

function cAxios() {
  // 保存请求拦截器中的回调函数
  this.saveReqFn = []
  // 保存响应拦截器中的回调函数
  this.saveResFn = []
  // 保存请求的数据
  this.data = []
  let _this = this
  this.interceptors = {
    request(fn) {
      _this.saveReqFn.push(fn)
    },
    response(fn) {
      _this.saveResFn.push(fn)
    }
  }
}

如何调用?

比如在post方法中,请求拦截器应该发送请求之前调用,响应拦截器在返回数据之前调用

cAxios.prototype.post = function (method, url, data) {
  // 保存请求的数据
  this.data = data
  let _this = this
  // 在发送请求之前调用请求拦截器的回调函数
  if (this.saveReqFn?.length) {
    this.saveReqFn.forEach(fn => {
      fn(this)
    })
  }
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()
    xhr.open(method, url)
    setHeaders(xhr, this.headers)
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status === 200 || xhr.status === 304) {
          // 创建一个新的对象,将响应的数据保存到新的对象中
          let newData = {}
          newData.data = JSON.parse(xhr.responseText)
          // 在返回数据之前调用响应拦截器的回调函数
          if (_this.saveResFn?.length) {
            _this.saveResFn.forEach(fn => {
              fn(newData)
            })
          }
          resolve(xhr.responseText)
        } else {
          reject(new Error(xhr.statusText))
        }
      }
    }
    xhr.send(JSON.stringify(data))
  })
}

4.完整代码


function cAxios() {
  // 保存请求拦截器中的回调函数
  this.saveReqFn = []
  // 保存响应拦截器中的回调函数
  this.saveResFn = []
  // 保存请求的数据
  this.data = []
  let _this = this
  this.interceptors = {
    request(fn) {
      _this.saveReqFn.push(fn)
    },
    response(fn) {
      _this.saveResFn.push(fn)
    }
  }
}

function setHeaders(xhr, headers) {
  for (let key in headers) {
    xhr.setquestHeader(key, headers[key])
  }
}

cAxios.prototype.create = function (obj) {
  let axios = new cAxios()
  axios.headers = obj.headers;
  axios.baseUrl = obj.baseUrl;
  return axios
}

cAxios.prototype.post = function (method, url, data) {
  // 保存请求的数据
  this.data = data
  let _this = this
  // 在发送请求之前调用请求拦截器的回调函数
  if (this.saveReqFn?.length) {
    this.saveReqFn.forEach(fn => {
      fn(this)
    })
  }
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()
    xhr.open(method, url)
    setHeaders(xhr, this.headers)
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status === 200 || xhr.status === 304) {
          // 创建一个新的对象,将请求的数据保存到新的对象中
          let newData = {}
          newData.data = JSON.parse(xhr.responseText)
          // 在返回数据之前调用响应拦截器的回调函数
          if (_this.saveResFn?.length) {
            _this.saveResFn.forEach(fn => {
              fn(newData)
            })
          }
          resolve(xhr.responseText)
        } else {
          reject(new Error(xhr.statusText))
        }
      }
    }
    xhr.send(JSON.stringify(data))
  })
}

let axios = new cAxios()

export {
  axios
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值