手写实现Ajax-2020

一、什么是Ajax?

Ajax是一种技术,不是某种东西。它的主要作用是向服务器发起异步请求,并在不刷新页面的前提下将请求而来的数据更新到网页上对应的位置(也就是局部更新)。
举个栗子:一个网页中有一个按钮和一个文本框,点击一次按钮就向服务器请求新的数据并将数据更新到文本框中。
如果这个网页没有使用Ajax请求数据,那么每点击一次按钮,整个页面会刷新,在刷新完成之后,文本框中的内容才会更新。在请求完成前,你不能操作网页上的其他内容
如果这个网页使用了Ajax请求数据,那么点击按钮之后,页面不刷新,文本框中的内容也会更新。在请求完成前,你可以随便操作其他内容

二、捋捋思路

实现Ajax的过程大体上可分为:

  1. 创建XMLHttpRequest对象的实例
  2. 创建响应函数
  3. 打开连接
  4. 发送请求

需要留意的有兼容性问题(因为某些浏览器莫得XMLHttpRequest对象)和发送请求的方式(get和post等等)

三、开整

get 版 ajax

	//接收两个参数,请求路径和请求成功时的回调函数
    function ajax(url, successFn) {
      //创建XMLHttpRequest对象的实例 并作兼容性处理
      let xhr;
      if (window.XMLHttpRequest) {
        xhr = new XMLHttpRequest()
      }
      //ie低版本的浏览器中没有XMLHttpRequest对象,但我们可以通过 ActiveXObject对象来创建XMLHttpRequest实例
      else if (window.ActiveXObject) {
        xhr = new ActiveXObject('Microsoft.XMLHTTP')
      }
	  //最坏的情况,我们只能报错
      if (xhr == null) {
        throw new Error('你的浏览器不支持XMLHTTP')
      }

	  //打开请求连接,三个参数分别对应的是:请求方式&请求地址&是否支持异步(true为支持)
      xhr.open('GET', url, true);
      //创建响应函数  -----注释①
      xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
          if (xhr.status === 200) {
          	//请求成功,用传入的successFn函数对请求结果进行对应处理
            successFn(xhr.responseText)
          }
          //这里可能返回的状态码有很多种,这里以404为例
          else if(xhr.status === 404){
            throw new Error('404 not found')
          }
        }
      }
      //发送请求
      xhr.send(null)
    }

注释①:
当readystate变化时,会触发xhr的onreadystatechange方法。当readystate等于4时,我们可以在这个方法中对接收到的数据进行处理。
在ajax请求中,readystate的值会随着请求各阶段的变化而变化,其中一共有五个值
0 - 尚未调用open方法
1 - 已经调用open,但尚未发送请求没调用send
2 - 已经发送请求已经调用了send
3 - 请求处理中此时因为响应及http头不全,贸然使用response系列方法获取数据可能会出现部分数据错误
4 - 请求完成可以获取到请求返回的数据

post 版 ajax

    function ajax(url, successFn) {
      let xhr;
      if (window.XMLHttpRequest) {
        xhr = new XMLHttpRequest()
      }else if (window.ActiveXObject) {
        xhr = new ActiveXObject('Microsoft.XMLHTTP')
      }
      if (xhr == null) {
        throw new Error('你的浏览器不支持XMLHTTP')
      }
      
      xhr.open('POST', url, true);
      //发送POST请求需要设置请求头(以表单的形式提交数据)
      xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
      
      xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
          if (xhr.status === 200) {
            successFn(xhr.responseText)
          }
          else if(xhr.status === 404){
            throw new Error('404 not found')
          }
        }
      }
      //POST请求发送时必须携带上相应的参数
      xhr.send("data=要发送的数据&name=cdb")
      //如果要提交的数据很多,可以包装成一个对象
      //let data = {
      //	"name":"cdb","age":"30"
      //	}
      //xhr.send(data)
    }

这样就欧克了,咱们这里将get请求和post请求单独拿出来是为了展示这两种请求方式的区别,实际上,咱们在使用Ajax时发送请求的方式是由我们自己定的。所以,我们最终的ajax方法应该接收三个参数(请求方式请求地址成功时的回调函数)。在方法内部我们进行判断请求方式,再根据请求方式执行对应的代码。这里我们就不展示了。

四、ajax终极版

我们的ajax还有一个缺陷,如果在一个请求成功的回调函数中再次发起请求,如下:

ajax(url,function(){
      console.log(`第一次请求到的数据`);
      ajax(url1,function(){
          console.log(`第二次请求到的数据`);
          ajax(url2,function(){
              console.log(`第三次请求到的数据`);
        })
      })
    })

此时,我们可以直观的看出,只有第一个请求成功了,第二个请求才能发起,第二个请求成功了,第三个请求才能发起……如果再多几个请求,emmm,想想是不是都头大。这些回调函数这么嵌套在一起,就形成了回调地狱所以,为了解决这个问题,我们可以让我们的ajax方法Promise结合在一起。(禁止套娃版ajax)

这里我们就以上面的get版ajax为基础进行改良。

	//因为我们使用了Promise,所以这里就不需要再传入成功时的回调函数了(Promise中的resolve()能代替它)
	function ajax(url){
	  //返回一个Promise
	  return new Promise((resolve,reject)=>{
	    let xhr = new XMLHttpRequest();
	    xhr.open('GET',url,true);
	    xhr.onreadystatechange = function(){
	      if(xhr.readyState === 4){
	        if(xhr.status === 200){
	          //成功请求到数据,通过resolve()将结果传递出去
	          resolve(xhr.responseText)
	        }
	        if(xhr.status === 404){
	          //请求失败,通过reject()传出错误信息
	          reject(new Error(`404 not found`))
	        }
	      }
	    }
	    xhr.send(null)
	  })
	}

大功告成!当我们使用终极版ajax再遇见上面那种情况时,嘿嘿嘿……

	ajax(url)
	.then(res1 => {
	  console.log(`第一次请求到的数据${res1}`)
	  return ajax(url1)
	 },err=>{console.log(err);})
	 
	.then(res2 => {
	  console.log(`第二次请求到的数据${res2}`)
	  return ajax(url2)
	 },err=>{ console.log(err)})
	 
	.then(res3 => {
	  console.log(`第三次请求到的数据${res3}`)
	 },err => {console.log(err)})      

这样子我们在读这段代码和维护这段代码的时候体验就好多了。

本文有些地方可能因个人理解有限而出现纰漏,还请大拿不吝赐教,留言指出,我再作修改(手动抱拳~)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值