详解原生Ajax的实现,并模仿JQuery进行封装(下)

简介: 接上文。

四、封装Ajax


文章开头提到,JQuery早已对Ajax请求进行了成熟的封装,所以我们可以借鉴它,甚至尽可能地去模仿它进行封装,在这之前,我们得先了解JQuery中Ajax的使用


(1)JQuery中的Ajax


这里我找来了几段使用JQuery发送Ajax请求的代码,如下所示:


  • 发送get请求


$.get('example.php', {query: 4, em: 0}, function(data, status, xhr) {
 console.log(`
  返回的数据为${data}
  返回的状态为${status}
  返回xhr对象为${xhr}
 `)
}, 'json')


这段代码发送了一个 get 请求,携带的参数有 query 值为 4em 值为 0,规定返回的数据类型为 json,同时设定了一个回调函数用于接收请求返回的数据、状态和xhr对象


  • 发送post请求


$.post('example.php', {query: 4, em: 0}, function(data, status, xhr) {
 console.log(`
  返回的数据为${data}
  返回的状态为${status}
  返回xhr对象为${xhr}
 `)
}, 'json')


这段代码发送了一个 post 请求,携带的参数有 query 值为 4em 值为 0,规定返回的数据类型为 json,同时设定了一个回调函数用于接收请求返回的数据、状态和xhr对象


  • 综合方法


// 该方法既可以发送get请求又可以发送post请求
$.ajax({
 url: 'example.php', // 请求的URL
 type: 'get', //请求类型,若为post,则表示发送post请求
 data: {query: 4, em: 0},     // 请求携带数据
 dataType: 'json',  // 接收的数据类型
 isAsync: true     // 是否异步请求
})
.then(data => {
 console.log(`请求成功,数据为${data}`)
})
.catch(err => {
 console.log(`请求失败,状态为${err}`)
})


其调用的是一个综合的方法,传入的参数是一个对象,对象中传入多个参数。这段代码是发送了一个 get 请求,地址为 example.php,携带的参数有 query 值为 4em 值为 0,所接收返回数据的类型为 json,请求为异步请求


特别的是,该方法的回调函数是通过 promise 实现的,即该方法返回一个 promise 对象,在 then 函数中处理请求成功的情况,在 catch 函数中处理请求失败的情况


若没有了解过 promise 的小伙伴建议先花几分钟了解一下,因为这是异步编程最常用的一个语法,下面放上文章链接——深入了解Promise对象,写出优雅的回调代码,告别回调地狱


接下来我们就针对上述给出的例子,逐个封装


(2)封装准备工作


因为 XMLHttpRequest 对象有一定的兼容性,因此我们在封装ajax方法之前可以先封装一个方法用来动态创建一个兼容性稍微好点的XHR对象(其中主要是兼容IE5和IE6)


我们都知道JQuery都是将方法封装在一个名为 $ 的对象中的,我们也这么做


let $ = {
 createXHR: function() {
  // 若浏览器支持,则创建XMLHttpRequest对象
  if(window.XMLHttpRequest) {
   return new XMLHttpRequest()
  } 
  // 若不支持,则创建ActiveXobject对象
  else {
   return new ActiveXObject()
  } 
 }
}


(3)封装$.get方法


首先查阅JQuery的 get 方法可知,其接收四个参数:URLdatacallbackdataType,分别表示请求的url地址、携带的参数、成功回调函数、返回数据的类型


let $ = {
 // 动态生成XHR对象的方法
 createXHR: function() {
  if(window.XMLHttpRequest) {
   return new XMLHttpRequest()
  } else {
   return new ActiveXObject()
  } 
 },
 get: function(url, data, callback, dataType) {
  // 避免dataType大小写的问题
  let dataType = dataType.toLowerCase()
  // 如果有传入data,则在url后面跟上参数
  if(data) {
   url += '?'
   Object.keys(data).forEach(key => url += `${key}=${data[key]}&`)
   url = url.slice(0, -1)
  }
  // 调用我们封装的方法生成XHR对象
  let xhr = this.createXHR()
  // 创建get请求
  xhr.open('get', url)
  // 发送请求
  xhr.send()
  xhr.onreadystatechange = function() {
   if(xhr.readyState === 4) {
    if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
     // 若dataType为json,则将返回的数据通过JSON.parse格式化
     let res = dataType === 'json' ? JSON.parse(xhr.responseText) : xhr.responseText
     // 调用回调函数,并把参数传进去
     callback(res, xhr.status, xhr)
    }
   }
  }
 },
}


(4)封装$.post方法


JQuery的 post 方法传入的参数跟 get 方法一样,只不过其内部的实现有略微的区别,就是携带参数的发送不一样,所以直接来看代码吧


let $ = {
 // 动态生成XHR对象的方法
 createXHR: function() {
  if(window.XMLHttpRequest) {
   return new XMLHttpRequest()
  } else {
   return new ActiveXObject()
  } 
 },
 post: function(url, data, callback, dataType) {
  // 避免dataType大小写的问题
  let dataType = dataType.toLowerCase()
  // 调用我们封装的方法动态生成XHR对象
  let xhr = this.createXHR()
  let str = ''
  // 若传入参数,则将参数序列化
  if(data) {
   Object.keys(data).forEach(key => str += `${key}=${data[key]}&`)
   str = str.slice(0, -1)
  }
  // 设置头部信息
  xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
  // 发送请求,并携带参数
  xhr.send(str)
  xhr.onreadystatechange = function() {
   if(xhr.readyState === 4) {
    if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
     // 若dataType为json,则将返回的数据通过JSON.parse格式化
     let res = dataType === 'json' ? JSON.parse(xhr.responseText) : xhr.responseText
     // 调用回调函数,把对应参数传进去
     callback(res, xhr.status, xhr)
    }
   }
  }
 }
}


(5)封装$.ajax方法


在JQuery中还有一个 ajax 方法,其既可以发送 get 请求,也可以发送 post 请求,该方法可传入多种参数,且支持 promise 处理回调函数


let $ = {
 createXHR: function() {
  if(window.XMLHttpRequest) {
   return new XMLHttpRequest()
  } else {
   return new ActiveXObject()
  } 
 },
 ajax: function(params) {
  // 初始化参数
  let type = params.type ? params.type.toLowerCase() : 'get'
  let isAsync = params.isAsync ? params.isAsync : 'true'
  let url = params.url
  let data = params.data ? params.data : {}
  let dataType = params.dataType.toLowerCase()
  // 用我们封装的方法动态生成XHR对象
  let xhr = this.createXHR()
  let str = ''
  // 拼接字符串
  Object.keys(data).forEach(key => str += `${key}=${data[key]}&`)
  str = str.slice(0, -1)
  // 如果是get请求就把携带参数拼接到url后面
  if(type === 'get') url += `?${str}`;
  // 返回promise对象,便于外部then和catch函数调用
  return new Promise((resolve, reject) => {
   // 创建请求
   xhr.open(type, url, isAsync)
   if(type === 'post') {
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-rulencoded')
    xhr.send(str)
   } else {
    xhr.send()
   }
   xhr.onreadystatechange = function() {
    if(xhr.readyState === 4) {
     if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
      let res = dataType === 'json' ? JSON.parse(xhr.responseText) : xhr.responseText
      resolve(res) // 请求成功,返回数据
     } else {
      reject(xhr.status) // 请求失败,返回状态码
     }
    }
   }
  }) 
 }
}


五、Ajax的约束


默认情况下,Ajax一般只能向同源的域发送请求,这是受到了浏览器的同源策略的限制,关于同源策略,你们可以去看一下我以前写过的一篇博客,里面写了同源策略的定义以及解决方案——前端人员都懂的浏览器的同源策略,以及如何进行不同源间的相互访问


了解过同源策略以后,我们来看看如何让Ajax不受同源策略的限制而成功发送请求。

CORS(跨域资源共享)要求我们在发送请求时自定义一个HTTP头部与服务器进行沟通,我们只需要设置一个名为 Origin 的头部,值为当前页面的源信息(协议、域名、端口),例如 Origin : http://example.com ;然后服务器需要设置一个名为 Access-Control-Allow-Origin 的响应头部,其值为允许跨域访问的源信息,若服务器设置的 Access-Control-Allow-Origin 与我们设置的 Origin 相同,则表示服务器允许我们跨域请求其资源,或者服务器可以将 Access-Control-Allow-Origin 值设为 *,此时表示允许任何域向其发送请求并且不受同源策略的限制。


现在的大部分浏览器几乎都支持了在发送Ajax请求后,自动向请求头部添加当前的源信息


六、结束语


建议你们好好了解JS的Ajax的使用,这样在面试中问起来你还能说出个一二三,并且有时候面试官还会直接让你亲手写一个简单的Ajax请求呢,而不会让你使用JQuery的。


看了本文,想必面试官如果让你当场封装一个类似JQuery的Ajax请求,你也不会手足无措呢。


相关文章
|
7月前
|
前端开发 JavaScript
杨校老师课堂之基于Servlet整合JQuery中的Ajax进行表单提交[基于IDEA]
杨校老师课堂之基于Servlet整合JQuery中的Ajax进行表单提交[基于IDEA]
58 0
|
3月前
|
前端开发 JavaScript 数据处理
JQuery 拦截请求 | Ajax 请求拦截
【10月更文挑战第4天】
168 1
|
4月前
|
JSON 前端开发 JavaScript
jQuery AJAX 方法
jQuery AJAX 方法
50 1
|
4月前
|
JSON JavaScript 前端开发
Jquery常用操作汇总,dom操作,ajax请求
本文汇总了jQuery的一些常用操作,包括DOM元素的选择、添加、移除,表单操作,以及如何使用jQuery发送Ajax请求,涵盖了GET、POST请求和文件上传等常见场景。
|
4月前
|
JSON 前端开发 JavaScript
jQuery AJAX 方法
jQuery AJAX 方法
32 1
|
5月前
|
前端开发 JavaScript Java
SpringBoot+JQuery+Ajax实现表单数据传输和单文件或多文件的上传
关于如何在SpringBoot项目中结合JQuery和Ajax实现表单数据的传输以及单文件或多文件上传的教程。文章提供了完整的前后端示例代码,包括项目的`pom.xml`依赖配置、SpringBoot的启动类`App.java`、静态资源配置`ResourceConfig.java`、配置文件`application.yml`、前端HTML页面(单文件上传和多文件上传加表单内容)以及后端控制器`UserController.java`。文章最后展示了运行结果的截图。
335 0
SpringBoot+JQuery+Ajax实现表单数据传输和单文件或多文件的上传
|
5月前
|
Devops 持续交付 测试技术
JSF遇上DevOps:开发流程将迎巨变?一篇文章带你领略高效协同的魅力!
【8月更文挑战第31天】本文探讨了如何在JavaServer Faces(JSF)开发中融入DevOps文化,通过持续集成与部署、自动化测试、监控与日志记录及反馈机制,提升软件交付速度与质量。文中详细介绍了使用Jenkins进行自动化部署、JUnit与Selenium进行自动化测试、ELK Stack进行日志监控的具体方法,并强调了持续改进的重要性。
49 0
|
5月前
|
XML JSON 前端开发
AJAX是什么?原生语法格式?jQuery提供分装好的AJAX有什么区别?
AJAX是什么?原生语法格式?jQuery提供分装好的AJAX有什么区别?
41 0
|
5月前
|
JavaScript 前端开发
Ajax的使用(jquery的下载)
这篇文章是关于Ajax学习笔记的分享,包括JQuery的下载方式、Ajax的主要参数说明,以及如何在网页中使用Ajax进行异步请求的示例代码。
|
7月前
|
JavaScript 前端开发 安全
安全开发-JS应用&原生开发&JQuery库&Ajax技术&加密编码库&断点调试&逆向分析&元素属性操作
安全开发-JS应用&原生开发&JQuery库&Ajax技术&加密编码库&断点调试&逆向分析&元素属性操作