摘要

在vue中,我们调用接口使用的都是axios,使用之前我们也会进行一定的封装,然后再进行使用。

在这里,我们主要说一下axios的实现原理,以及如何使用原生的js来自己封装出一个axios。

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

1.post方法

在我们写方法之前,肯定是要先自己写一个类出来,里面的内容先不用写。

然后再在类的下面写出post的方法:

function iaxios () {
}
iaxios.prototype.post = function (url, data){
}

OK,现在我们来实现这个方法。

如果我们想用原生的js来实现post请求,我们应该这样做:

    var xhr = new XMLHttpRequest();
    xhr.open('post', url, true);
    xhr.onreadystatechange = function () {
      if (xhr.readyState == 4) {
        if ((xhr.status == 200 || xhr.status == 304)) {
          resolve(xhr.responseText)
        } else {
          reject(xhr.responseText)
        }
      }
    };
    xhr.send(data)

但是我们直接把这段代码放进去的话,会有一点问题:

1.官方的axios返回的是一个promise对象

2.官方的axios.post方法传的data参数是一个对象,原生的是一个字符串

所以为了解决第一个问题,我们可以在方法内返回一个promise对象,而第二个问题可以使用JSON.stringfy()这个方法解决。

iaxios.prototype.post = function (url, data) {
  //返回promise对象
  return new Promise((resolve, reject) => {
    var xhr = new XMLHttpRequest();
    xhr.open('post', url, true);
    xhr.onreadystatechange = function () {
      if (xhr.readyState == 4) {
        if ((xhr.status == 200 || xhr.status == 304)) {
          resolve(xhr.responseText)
        } else {
          reject(xhr.responseText)
        }
      }
    };
    xhr.send(JSON.stringify(data))
  })
}

这样我们就实现了post的这个方法了。

而对get方法这里就不再写一遍了(写的时候主要注意参数的问题就可以了)。

2.create方法

首先我们知道,axios的create方法主要是对请求头等参数的配置,而这个方法同样也会返回一个axios的实例,这个实例可以继续使用post等方法。

所以我们首先想到的是,这个方法应该返回一个实例对象,而这个实例对象下的属性会根据传进来的对象设置。

这里面我只列举两个属性:

iaxios.prototype.create = function (obj) {
  var emaxios = new iaxios()
  emaxios.headers = obj.headers;
  emaxios.baseUrl = obj.baseUrl;
  return emaxios;
}

但是我们调用完这个create方法后,我们已经有了一些配置,如果再调用post等方法,我们应该是携带着这些参数去调用psot方法,所以在post方法内我们也要修改一下。

我们首先写一个配置请求头的方法:

function setHeader (xhr, headers) {
  for (var i in headers) {
    xhr.setRequestHeader(i, headers[i]);
  }
}

然后在post方法内,在ajax请求发送之前调用这个方法就可以了:

    setHeader(xhr, this.headers);

3.拦截器

在axios中,拦截器分两种,分别是请求拦截和响应拦截。

二者的作用也是相差不多的,一个是希望在请求之前做什么,一个是希望在请求之后做什么。

我们先来写一下请求拦截(这里面不考虑use):

我们先想一下,interceptors一定是一个对象,并且下面有两个属性,分别是request和response。

那么我们就在类里面写一下:

function iaxios () {
  this.interceptors = {
    request (cb) {
    },
    response (aa) {
    },
  }
}

如果我们想在外边调用这个方法,会将一个回调函数传进来,

所以在我们这里我们需要把这个回调函数保存下来(考虑到有多个拦截器,所以我们采用数组保存)。

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

function iaxios () {
  //保存拦截器中的回调函数
  this.saveRequest = []
  this.saveResponse = []
  //保存请求的数据
  this.data = {};
  let _this = this;
  this.interceptors = {
    request (cb) {
      _this.saveRequest.push(cb)
    },
    response (aa) {
      _this.saveResponse.push(aa)
    },
  }
}

现在拦截器的方法已经写好了,我们应该在什么时候调用呢?

请求拦截一定是在请求发送之前进行调用,我们拿post来举例子:

iaxios.prototype.post = function (url, data) {
  this.data = data;
  let _this = this;
  // this.saveRequest && this.saveRequest(this)
  //请求之前调用请求拦截的回调函数
  if (this.saveRequest) {
    this.saveRequest.forEach(fn => {
      fn(this)
    })
  }

我们只需要在请求之前,把想要传递的数据copy下来(用于当作参数)。

然后循环调用我们保存下来的方法(其实就是调用的时候传递回调函数)

这样就能实现请求拦截了。

那么响应拦截一定是在返回响应数据之前调用了:

        if ((xhr.status == 200 || xhr.status == 304)) {
          //用来保存返回的数据
          let newRespose = new Object;
          newRespose.data = JSON.parse(xhr.responseText);
          //在返回数据之前调用相应拦截器的回调函数
          if (_this.saveResponse) {
            _this.saveResponse.forEach(fn => {
              fn(newRespose)
            })
          }
          resolve(newRespose.data)

这里面我们创建的newRespose也是为了当作参数传递到响应拦截的方法里面。

这样的话响应拦截器的实现也完成了。

4.代码

最后再把整体的代码复制一份:

// const { resolve, reject } = require("core-js/fn/promise")
function iaxios () {
  //保存拦截器中的回调函数
  this.saveRequest = []
  this.saveResponse = []
  //保存请求的数据
  this.data = {};
  let _this = this;
  this.interceptors = {
    request (cb) {
      _this.saveRequest.push(cb)
    },
    response (aa) {
      _this.saveResponse.push(aa)
    },
  }
}
iaxios.prototype.post = function (url, data) {
  this.data = data;
  let _this = this;
  // this.saveRequest && this.saveRequest(this)
  //请求之前调用请求拦截的回调函数
  if (this.saveRequest) {
    this.saveRequest.forEach(fn => {
      fn(this)
    })
  }
  //返回promise对象
  return new Promise((resolve, reject) => {
    var xhr = new XMLHttpRequest();
    xhr.open('post', url, true);
    //设置请求头的配置
    setHeader(xhr, this.headers);
    xhr.onreadystatechange = function () {
      if (xhr.readyState == 4) {
        if ((xhr.status == 200 || xhr.status == 304)) {
          //用来保存返回的数据
          let newRespose = new Object;
          newRespose.data = JSON.parse(xhr.responseText);
          // _this.saveResponse && _this.saveResponse(newRespose)
          //在返回数据之前调用相应拦截器的回调函数
          if (_this.saveResponse) {
            _this.saveResponse.forEach(fn => {
              fn(newRespose)
            })
          }
          resolve(newRespose.data)
        } else {
          reject(xhr.responseText)
        }
      }
    };
    xhr.send(JSON.stringify(data))
  })
}
iaxios.prototype.get = function (url) {
  let _this = this;
  // this.saveRequest && this.saveRequest(this)
  //请求之前调用请求拦截的回调函数
  if (this.saveRequest) {
    this.saveRequest.forEach(fn => {
      fn(this)
    })
  }
  //返回promise对象
  return new Promise((resolve, reject) => {
    var xhr = new XMLHttpRequest();
    xhr.open('get', url, true);
    //设置请求头的配置
    setHeader(xhr, this.headers);
    xhr.onreadystatechange = function () {
      if (xhr.readyState == 4) {
        if ((xhr.status == 200 || xhr.status == 304)) {
          //用来保存返回的数据
          let newRespose = new Object;
          newRespose.data = JSON.parse(xhr.responseText);
          // _this.saveResponse && _this.saveResponse(newRespose)
          //在返回数据之前调用相应拦截器的回调函数
          if (_this.saveResponse) {
            _this.saveResponse.forEach(fn => {
              fn(newRespose)
            })
          }
          resolve(newRespose.data)
        } else {
          reject(xhr.responseText)
        }
      }
    };
    xhr.send()
  })
}
//返回一个新的实例并且复制obj的属性
iaxios.prototype.create = function (obj) {
  var emaxios = new iaxios()
  emaxios.headers = obj.headers;
  emaxios.baseUrl = obj.baseUrl;
  return emaxios;
}
//设置请求头的方法
function setHeader (xhr, headers) {
  for (var i in headers) {
    xhr.setRequestHeader(i, headers[i]);
  }
}
var taxios = new iaxios();
export {
  taxios
}

到此这篇关于JavaScript封装axios的实现详解的文章就介绍到这了,更多相关JS封装axios内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

JavaScript封装axios的实现详解的更多相关文章

  1. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  2. HTML5数字输入仅接受整数的实现代码

    这篇文章主要介绍了HTML5数字输入仅接受整数的实现代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. amaze ui 的使用详细教程

    这篇文章主要介绍了amaze ui 的使用详细教程,本文通过多种方法给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  4. html5简介_动力节点Java学院整理

    这篇文章主要介绍了html5简介,用于指定构建网页的元素,这些元素中的大多数都用于描述网页内容,有兴趣的可以了解一下

  5. ios 8 Homescreen webapp,关闭和打开iPad停止javascript

    我有一个适用于iPad的全屏HTML5网络应用程序,并且刚刚安装了IOS8来试用它,它一切正常,直到你关闭并重新启动iPad.一旦web应用程序重新启动javascript就会停止并加载新页面不会重新启动它.在iPad上的Safari中打开同一页面时,关闭和打开iPad会继续按预期工作.其他人注意到了这个或想出了一个解决方案吗?解决方法这似乎是我在iOS8.1.1更新中解决的.

  6. iOS 6 javascript与object.defineProperty的间歇性问题

    当访问使用较新的Object.defineProperty语法定义属性的对象的属性时,有没有其他人注意到新iOS6javascript引擎中的间歇性错误/问题?https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty我正在看到javascript失败的情况,说

  7. ios – 如何使用JSExport导出内部类的方法

    解决方法似乎没有办法将内部类函数导出到javascript.我将内部类移出并创建了独立的类,它起作用了.

  8. 静音iOS推送通知与React Native应用程序在后台

    我有一个ReactNative应用程序,我试图获得一个发送到JavaScript处理程序的静默iOS推送通知.我看到的行为是AppDelegate中的didReceiveRemoteNotification函数被调用,但是我的JavaScript中的处理程序不会被调用,除非应用程序在前台,或者最近才被关闭.我很困惑的事情显然是应用程序正在被唤醒,并且它的didReceiveRemoteNotifi

  9. ios – 内存泄漏与UIWebView和Javascript

    清楚地包含一个Javascript文件到我的HTML是使UIWebView泄漏内存.当我重复使用相同的UIWebView对象时,或者每当我有内容实例化一个新的漏洞时,会出现泄漏的事实,导致我认为必须有一些JavaScript文件被loadHTMLString处理,导致泄漏.有人知道如何解决这个问题吗?

  10. iOS应用程序的UI自动化测试如何与乐器和Javascript

    从WWDC2010视频会议中了解iOS应用程序的自动化UI测试,但没有实践.从代码项目project,我们可以有一个例子.这个问题在这里听到有涉及这个的人.任何限制?解决方法我建议从AlexWollmer开始使用thisblogpost.他创建了一个非常有用的JavaScript库:tuneup_jswithtest()函数,它允许测试分离和有用的帮助者以及为自动化仪器编写测试的断言.

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部