原生JS发送异步数据请求


Posted in Javascript onJune 08, 2017

在做项目的时候,有时候需要用到异步数据请求,但是如果这个时候没有框架的依赖,就需要用到原生JS进行异步数据请求。这时候无非有两种请求方式,一种是AJAX,另一个是JSONP。通过原生JS对异步请求进行简单的封装。

AJAX

AJAX是一种数据请求方式,不需要刷新整个页面就能够更新局部页面的数据。AJAX的技术核心是XMLHttpRequest对象,主要请求过程如下:

  • 创建XMLHttpRequest对象(new)
  • 连接服务器(open)
  • 发送请求(send)
  • 接收响应数据(onreadystatechange)

不说话直接贴代码

/**
* 通过JSON的方式请求
* @param {[type]} params [description]
* @return {[type]}  [description]
*/
ajaxJSON(params) {
 params.type = (params.type || 'GET').toUpperCase();
 params.data = params.data || {};
 var formatedParams = this.formateParams(params.data, params.cache);
 var xhr;
 //创建XMLHttpRequest对象
 if (window.XMLHttpRequest) {
  //非IE6
  xhr = new XMLHttpRequest();
 } else {
  xhr = new ActiveXObject('Microsoft.XMLHTTP');
 }
 //异步状态发生改变,接收响应数据
 xhr.onreadystatechange = function() {
  if (xhr.readyState == 4 && xhr.status == 200) {
   if (!!params.success) {
    if (typeof xhr.responseText == 'string') {
     params.success(JSON.parse(xhr.responseText));
    } else {
     params.success(xhr.responseText);
    }
   }
  } else {
   params.error && params.error(status);
  }
 }
 if (params.type == 'GET') {
  //连接服务器
  xhr.open('GET', (!!formatedParams ? params.url + '?' + formatedParams : params.url), true);
  //发送请求
  xhr.send();
 } else {
  //连接服务器
  xhr.open('POST', params.url, true);
  xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  //发送请求
  xhr.send(formatedParams);
 }
},
/**
* 格式化数据
* @param {Obj}  data 需要格式化的数据
* @param {Boolean} isCache 是否加入随机参数
* @return {String}   返回的字符串
*/
formateParams: function(data, isCache) {
 var arr = [];
 for (var name in data) {
  arr.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name]));
 }
 if (isCache) {
  arr.push('v=' + (new Date()).getTime());
 }
 return arr.join('&');
}

IE7及其以上版本中支持原生的 XHR 对象,因此可以直接用:var oAjax = new XMLHttpRequest();。IE6及其之前的版本中,XHR对象是通过MSXML库中的一个ActiveXObject对象实现的。

通过xhr的open函数来连接服务器,主要接收三个参数:请求方式、请求地址和是否异步请求(一般都是异步请求)。请求方式有两种,GET和POST,GET是通过URL将数据提交到服务器的,POST则是通过将数据作为send方法的参数发送到服务器。

给xhr绑定状态改变函数onreadystatechange,主要用来检测xhr的readyState的变化,当异步发送成功后,readyState的数值会由0变成4,同时触发onreadystatechange事件。readyState的属性及对应状态如下:

0 (未初始化) 对象已建立,但是尚未初始化(尚未调用open方法)
1 (初始化) 对象已建立,尚未调用send方法
2 (发送数据) send方法已调用,但是当前的状态及http头未知
3 (数据传送中) 已接收部分数据,因为响应及http头不全,这时通过responseBody和responseText获取部分数据会出现错误
4 (完成) 数据接收完毕,此时可以通过通过responseBody和responseText获取完整的回应数据

在readystatechange事件中,先判断响应是否接收完成,然后判断服务器是否成功处理请求,xhr.status 是状态码,状态码以2开头的都是成功,304表示从缓存中获取,上面的代码在每次请求的时候都加入了随机数,所以不会从缓存中取值,故该状态不需判断。

JSONP

如果还是用上面的XMLHttpRequest对象来发送需要跨域的请求,虽然调用了send函数,但是xhr的状态一直都是0,也不会触发onreadystatechange事件,这个时候就要用到JSONP的请求方式了。

JSONP(JSON with Padding) 是一种跨域请求方式。主要原理是利用了script标签可以跨域请求的特点,由其src属性发送请求到服务器,服务器返回js代码,网页端接受响应,然后就直接执行了,这和通过script标签引用外部文件的原理是一样的。

JSONP由两部分组成:回调函数和数据,回调函数一般是由网页端控制,作为参数发往服务器端,服务器端把该函数和数据拼成字符串返回。

比如网页端创建一个script标签,并给其src赋值为http://www.test.com/json/?callback=process, 此时网页端就发起一个请求。服务端将要返回的数据拼作为函数的参数传入,服务端返回的数据格式类似”process({‘name:'xieyufei'})”,网页端接收到了响应值,因为请求者是 script,所以相当于直接调用process方法,并且传入了一个参数。

不说话直接贴代码。

/**
* 通过JSONP的方式请求
* @param {[type]} params [description]
* @return {[type]}  [description]
*/
ajaxJSONP(params) {
 params.data = params.data || {};
 params.jsonp = params.jsonp || 'callback';
 // 设置传递给后台的回调参数名和参数值
 var callbackName = 'jsonp_' + (new Date()).getTime();
 params.data[params.jsonp] = callbackName;
 var formatedParams = this.formateParams(params.data, params.cache);
 //创建script标签并插入到页面中
 var head = document.getElementsByTagName('head')[0];
 var script = document.createElement('script');
 head.appendChild(script);
 //创建jsonp回调函数 
 window[callbackName] = function(json) {
  head.removeChild(script);
  clearTimeout(script.timer);
  window[callbackName] = null;
  params.success && params.success(json);
 };
 //发送请求 
 script.src = (!!formatedParams ? params.url + '?' + formatedParams : params.url);
 //为了得知此次请求是否成功,设置超时处理
 if (params.time) {
  script.timer = setTimeout(function() {
   window[callbackName] = null;
   head.removeChild(script);
   params.error && params.error({
    message: '超时'
   });
  }, params.time);
 }
}

给script标签设置src属性时浏览器就会去发送请求,但是只能发送一次请求,导致script标签不能复用,因此每次操作完都需要把script标签移除。在浏览器发送请求之前给全局绑定一个回调函数,当数据请求成功时就会调用这个回调函数。

总结

将两种发送异步数据的方式整合起来,根据dataType来进行判断选用哪种方式。贴上完整的代码

var xyfAjax = {
 ajax: function(params) {
  params = params || {};
  params.cache = params.cache || false;
  if (!params.url) {
   throw new Error('参数不合法');
  }
  params.dataType = (params.dataType || 'json').toLowerCase();
  if (params.dataType == 'jsonp') {
   this.ajaxJSONP(params);
  } else if (params.dataType == 'json') {
   this.ajaxJSON(params);
  }
 },
 /**
 * 通过JSONP的方式请求
 * @param {[type]} params [description]
 * @return {[type]}  [description]
 */
 ajaxJSONP(params) {
  params.data = params.data || {};
  params.jsonp = params.jsonp || 'callback';
  // 设置传递给后台的回调参数名和参数值
  var callbackName = 'jsonp_' + (new Date()).getTime();
  params.data[params.jsonp] = callbackName;
  var formatedParams = this.formateParams(params.data, params.cache);
  //创建script标签并插入到页面中
  var head = document.getElementsByTagName('head')[0];
  var script = document.createElement('script');
  head.appendChild(script);
  //创建jsonp回调函数 
  window[callbackName] = function(json) {
   head.removeChild(script);
   clearTimeout(script.timer);
   window[callbackName] = null;
   params.success && params.success(json);
  };
  //发送请求 
  script.src = (!!formatedParams ? params.url + '?' + formatedParams : params.url);
  //为了得知此次请求是否成功,设置超时处理
  if (params.time) {
   script.timer = setTimeout(function() {
    window[callbackName] = null;
    head.removeChild(script);
    params.error && params.error({
     message: '超时'
    });
   }, params.time);
  }
 },
 /**
 * 通过JSON的方式请求
 * @param {[type]} params [description]
 * @return {[type]}  [description]
 */
 ajaxJSON(params) {
  params.type = (params.type || 'GET').toUpperCase();
  params.data = params.data || {};
  var formatedParams = this.formateParams(params.data, params.cache);
  var xhr;
  //创建XMLHttpRequest对象
  if (window.XMLHttpRequest) {
   //非IE6
   xhr = new XMLHttpRequest();
  } else {
   xhr = new ActiveXObject('Microsoft.XMLHTTP');
  }
  //异步状态发生改变,接收响应数据
  xhr.onreadystatechange = function() {
   if (xhr.readyState == 4 && xhr.status == 200) {
    if (!!params.success) {
     if (typeof xhr.responseText == 'string') {
      params.success(JSON.parse(xhr.responseText));
     } else {
      params.success(xhr.responseText);
     }
    }
   } else {
    params.error && params.error(status);
   }
  }
  if (params.type == 'GET') {
   //连接服务器
   xhr.open('GET', (!!formatedParams ? params.url + '?' + formatedParams : params.url), true);
   //发送请求
   xhr.send(null);
  } else {
   //连接服务器
   xhr.open('POST', params.url, true);
   xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
   //发送请求
   xhr.send(formatedParams);
  }
 },
 /**
 * 格式化数据
 * @param {Obj}  data 需要格式化的数据
 * @param {Boolean} isCache 是否加入随机参数
 * @return {String}   返回的字符串
 */
 formateParams: function(data, isCache) {
  var arr = [];
  for (var name in data) {
   arr.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name]));
  }
  if (isCache) {
   arr.push('v=' + (new Date()).getTime());
  }
  return arr.join('&');
 }
}
xyfAjax.ajax({
 url:'http://www.xieyufei.com',
 type:'get', //or post
 dataType:'json', //or jsonp
 data:{
  name:'xyf'
 },
 success: function(data){
  console.log(data)
 }
})

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript使用cookie
Feb 02 Javascript
IE下使用cloneNode注意事项分享
Nov 22 Javascript
js实现广告漂浮效果的小例子
Jul 02 Javascript
JavaScript中对循环语句的优化技巧深入探讨
Jun 06 Javascript
浅谈Javascript中的Function与Object
Jan 26 Javascript
js实现对table的增加行和删除行的操作方法
Oct 13 Javascript
JS实现页面进入和返回定位到具体位置
Dec 08 Javascript
easyui datebox 时间限制,datebox开始时间限制结束时间,datebox截止日期比起始日期大的实现代码
Jan 12 Javascript
@ResponseBody 和 @RequestBody 注解的区别
Mar 08 Javascript
vue与bootstrap实现时间选择器的示例代码
Aug 26 Javascript
解决VUE中document.body.scrollTop为0的问题
Sep 15 Javascript
点击按钮弹出模态框的一系列操作代码实例
Mar 29 Javascript
vue2 自定义动态组件所遇到的问题
Jun 08 #Javascript
vue.js中过滤器的使用教程
Jun 08 #Javascript
了解VUE的render函数的使用
Jun 08 #Javascript
Node.js 使用命令行工具检查更新
Jun 08 #Javascript
在vue.js中抽出公共代码的方法示例
Jun 08 #Javascript
Ionic3 UI组件之autocomplete详解
Jun 08 #Javascript
jQuery+ajax实现局部刷新的两种方法
Jun 08 #jQuery
You might like
Yii框架form表单用法实例
2014/12/04 PHP
ThinkPHP中create()方法自动验证实例
2017/04/26 PHP
利用PHP判断是否是连乘数字串的方法示例
2017/07/03 PHP
PHP使用ActiveMQ实现消息队列的方法详解
2019/05/31 PHP
jquery validate使用攻略 第四步
2010/07/01 Javascript
javascript高级程序设计第二版第十二章事件要点总结(常用的跨浏览器检测方法)
2012/08/22 Javascript
js函数的引用, 关于内存的开销
2012/09/17 Javascript
jQuery截取指定长度字符串的实现原理及代码
2014/07/01 Javascript
jquery实现类似EasyUI的页面布局可改变左右的宽度
2020/09/12 Javascript
使用vue.js开发时一些注意事项
2016/04/27 Javascript
jQuery插件Easyui设置datagrid的pageNumber导致两次请求问题的解决方法
2016/08/06 Javascript
javascript Function函数理解与实战
2017/12/01 Javascript
vue2中,根据list的id进入对应的详情页并修改title方法
2018/08/24 Javascript
2019 年编写现代 JavaScript 代码的5个小技巧(小结)
2019/01/15 Javascript
JavaScript中break、continue和return的用法区别实例分析
2020/03/02 Javascript
Python读取mp3中ID3信息的方法
2015/03/05 Python
Python中datetime常用时间处理方法
2015/06/15 Python
python中print的不换行即时输出的快速解决方法
2016/07/20 Python
python3中int(整型)的使用教程
2017/03/23 Python
Python wxpython模块响应鼠标拖动事件操作示例
2018/08/23 Python
python os.path模块常用方法实例详解
2018/09/16 Python
Django如何使用第三方服务发送电子邮件
2019/08/14 Python
使用Python和OpenCV检测图像中的物体并将物体裁剪下来
2019/10/30 Python
详解如何在css中引入自定义字体(font-face)
2018/05/17 HTML / CSS
Kathmandu澳洲户外商店:新西兰户外运动品牌
2017/11/12 全球购物
wedgwood加拿大官网:1759年成立的英国国宝级陶瓷餐具品牌
2018/07/17 全球购物
购买美国制造的相框和画框架:Picture Frames
2018/08/14 全球购物
什么是"引用"?申明和使用"引用"要注意哪些问题?
2016/03/03 面试题
2013年高中生自我评价
2013/10/23 职场文书
网站开发实习生的自我评价
2013/12/11 职场文书
煤矿安全生产月活动总结
2014/07/05 职场文书
招标承诺书
2014/08/30 职场文书
最美家庭活动方案
2014/08/31 职场文书
小学学习委员竞选稿
2015/11/20 职场文书
2016年庆祝六一儿童节活动总结
2016/04/06 职场文书
JavaScript+HTML实现学生信息管理系统
2021/04/20 Javascript