jQuery ajax的功能实现方法详解


Posted in Javascript onJanuary 06, 2017

jQuery的ajax方法非常好用,这么好的东西,你想拥有一个属于自己的ajax么?接下来,我们来自己做一个简单的ajax吧。

实现功能

由于jq中的ajax方法是用了内置的deferred模块,是Promise模式的一种实现,而我们这里没有讲过,所以我们就不使用这一模式啦。

我们只定义一个ajax方法,他可以简单的get,post,jsonp请求就可以啦~~

var ajax = function () {
 // 做一些初始化,定义一些私有函数等
 return function () {
 // ajax主体代码
 }
}()
ajax({
 url: myUrl,
 type: 'get',
 dataType: 'json',
 timeout: 1000,
 success: function (data, status) {
 console.log(data)
 },
 fail: function (err, status) {
 console.log(err)
 }
})

我们的ajax方法最后实现的功能如上所示,非常类似于jq。那我们还在等什么,开始吧。

整体思路

我们的ajax方法需要传递一个对象进去,这个对象中我们可以定义一些我们希望的属性,我们就必须初始一下各种属性

//默认请求参数
 var _options = {
 url: null, // 请求连接
 type: 'GET', // 请求类型
 data: null, // post时请求体
 dataType: 'text', // 返回请求的类型,有text/json两种
 jsonp: 'callback', // jsonp请求的标志,一般不改动
 jsonpCallback: 'jsonpCallback', //jsonp请求的函数名
 async: true, // 是否异步
 cache: true, // 是否缓存
 timeout:null, // 设置请求超时
 contentType: 'application/x-www-form-urlencoded',
 success: null, // 请求成功回调函数
 fail: null // 请求失败回调
 }

以上我们定义了一大串请求有关的数据,接下来我们就开始ajax主体函数的书写,现在的ajax方法是这样了

var ajax = function () {
 //默认请求参数
 var _options = {
 url: null,
 type: 'GET',
 data: null,
 dataType: 'text',
 jsonp: 'callback',
 jsonpCallback: 'jsonpCallback',
 async: true,
 cache: true,
 timeout:null,
 contentType: 'application/x-www-form-urlencoded',
 success: null,
 fail: null
 }
 // ...
 return function (options) {
  // ...
 }
}()

我们可以想一下,ajax方法传递一个对象进来,我们是不是需要把我们设置的这个对象上的属性来覆盖掉初始化_options上面的那些属性呢,肯定需要。那下面我们先写一个简单的继承,如下:

var ajax = function () {
 //默认请求参数
 var _options = {
 url: null,
 type: 'GET',
 data: null,
 dataType: 'text',
 jsonp: 'callback',
 jsonpCallback: 'jsonpCallback',
 async: true,
 cache: true,
 timeout:null,
 contentType: 'application/x-www-form-urlencoded',
 success: null,
 fail: null
 }
 // 内部使用的继承方法
 var _extend = function(target,options) {
 if( typeof target !== 'object' || typeof options !== 'object' ) {
  return;
 }
 var copy ,clone, name;
 for( name in options ) {
  if(options.hasOwnProperty(name) && !target.hasOwnProperty(name)) {
  target[name] = options[name];
  }
 }
 return target;
 };
 // ...
 return function (options) {
 // 没有传参或者没有url,抛出错误
 if( !options || !options.url ) {
  throw('参数错误!');
 }
 // 继承操作
 options.type = options.type.toUpperCase();
 _extend(options,_options);
  // ...
 }
}()

这个继承方法,我们是把初始化的_options继承到了options,为什么呢?因为我们这个_options对象不在ajax方法内部,我们需要使用它,但我们不能改变他,如果改变了他,下一次使用ajax方法将会崩溃。因此,我们紧紧是把配置的options对象没有的属性设置为初始值。

下面,我们就要发送请求了么?等等!好像jsonp请求不是xhr请求啊,他好像是将请求url当做script标签的src值插入到页面body中去实现的,哦,对了,我们先把jsonp请求处理一下再开始建立xhr请求的代码吧。

var ajax = function () {
 //默认请求参数
 var _options = {
 url: null,
 type: 'GET',
 data: null,
 dataType: 'text',
 jsonp: 'callback',
 jsonpCallback: 'jsonpCallback',
 async: true,
 cache: true,
 timeout:null,
 contentType: 'application/x-www-form-urlencoded',
 success: null,
 fail: null
 }
 // 内部使用的继承方法
 var _extend = function(target,options) {
 if( typeof target !== 'object' || typeof options !== 'object' ) {
  return;
 }
 var copy ,clone, name;
 for( name in options ) {
  if(options.hasOwnProperty(name) && !target.hasOwnProperty(name)) {
  target[name] = options[name];
  }
 }
 return target;
 };
 // jsonp处理函数
 function _sendJsonpRequest(url,callbackName,succCallback) {
 var script = document.createElement('script');
 script.type="text/javascript";
 script.src=url;
 document.body.appendChild(script);
 // 如果用户自己定义了回调函数,就用自己定义的,否则,调用success函数
 window[callbackName] = window[callbackName] || succCallback;
 }
 // ...
 return function (options) {
 // 没有传参或者没有url,抛出错误
 if( !options || !options.url ) {
  throw('参数错误!');
 }
 // 继承操作
 options.type = options.type.toUpperCase();
 _extend(options,_options);
 /*jsonp部分,直接返回*/
 if( options.dataType === 'jsonp' ) {
  var jsonpUrl = options.url.indexOf('?') > -1 ? options.url: options.url +
  '?' + options.jsonp+ '=' + options.jsonpCallback;
  return _sendJsonpRequest(jsonpUrl,options.jsonpCallback,options.success);
 }
  // ...
 }
}()

我们定义了一个_sendJsonpRequest函数,这个函数接收三个参数,第一个是jsonpUrl,第二个是jsonp的回调函数名,第三个是成功回调函数,我们在这个函数内建立一个src为jsonpUrl的script元素插入到body中,同时,确定了回调函数(如果我们定义了jsonpCallback函数就调用它,如果没有就调用success回调,一般情况我们不去定义全局的jsonpCallback函数而传递success回调来完成jsonp请求)。

好,处理好jsonp请求后,我们开始处理xhr请求了。

var ajax = function () {
 //默认请求参数
 var _options = {
 url: null,
 type: 'GET',
 data: null,
 dataType: 'text',
 jsonp: 'callback',
 jsonpCallback: 'jsonpCallback',
 async: true,
 cache: true,
 timeout:null,
 contentType: 'application/x-www-form-urlencoded',
 success: null,
 fail: null
 }
 // 内部使用的继承方法
 var _extend = function(target,options) {
 if( typeof target !== 'object' || typeof options !== 'object' ) {
  return;
 }
 var copy ,clone, name;
 for( name in options ) {
  if(options.hasOwnProperty(name) && !target.hasOwnProperty(name)) {
  target[name] = options[name];
  }
 }
 return target;
 };
 // jsonp处理函数
 function _sendJsonpRequest(url,callbackName,succCallback) {
 var script = document.createElement('script');
 script.type="text/javascript";
 script.src=url;
 document.body.appendChild(script);
 // 如果用户自己定义了回调函数,就用自己定义的,否则,调用success函数
 window[callbackName] = window[callbackName] || succCallback;
 }
 // json转化为字符串
 var _param = function(data) {
 var str = '';
 if( !data || _empty(data)) {
  return str;
 }
 for(var key in data) {
  str += key + '='+ data[key]+'&'
 }
 str = str.slice(0,-1);
 return str;
 }
 //判断对象是否为空
 var _empty = function(obj) {
 for(var key in obj) {
  return false;
 }
 return true;
 }
 // ...
 return function (options) {
 // 没有传参或者没有url,抛出错误
 if( !options || !options.url ) {
  throw('参数错误!');
 }
 // 继承操作
 options.type = options.type.toUpperCase();
 _extend(options,_options);
 /*jsonp部分,直接返回*/
 if( options.dataType === 'jsonp' ) {
  var jsonpUrl = options.url.indexOf('?') > -1 ? options.url: options.url +
  '?' + options.jsonp+ '=' + options.jsonpCallback;
  return _sendJsonpRequest(jsonpUrl,options.jsonpCallback,options.success);
 }
  //XMLHttpRequest传参无影响
 var xhr = new (window.XMLHttpRequest || ActiveXObject)('Microsoft.XMLHTTP');
 // get搜索字符串
 var search = '';
 // 将data序列化
 var param= _param(options.data)
 if( options.type === 'GET' ) {
  search = (options.url.indexOf('?') > -1 ? '&' : '?') + param;
  if(!options.cache) {
  search += '&radom='+Math.random();
  }
  param = null;
 }
  // ...
 }
}()

首先,兼容ie创建xhr对象,XMLHttpRequest构造函数传递参数是无影响,然后我们定义了两个辅助变量:search、param,前者用于get请求的查询字串,后者用于post请求的send内容,我们定义了一个_param方法来讲对象转换为send方法参数的模式,就如你看到的那样,下面我们做了get与post之间合理的search、param的赋值工作。接下来我们就可以发送请求书写最激动人心的内容了。

最终的代码如下

;
var ajax = function () {
 //默认请求参数
 var _options = {
 url: null,
 type: 'GET',
 data: null,
 dataType: 'text',
 jsonp: 'callback',
 jsonpCallback: 'jsonpCallback',
 async: true,
 cache: true,
 timeout:null,
 contentType: 'application/x-www-form-urlencoded',
 success: null,
 fail: null
 }
 // json转化为字符串
 var _param = function(data) {
 var str = '';
 if( !data || _empty(data)) {
  return str;
 }
 for(var key in data) {
  str += key + '='+ data[key]+'&'
 }
 str = str.slice(0,-1);
 return str;
 }
 //判断对象是否为空
 var _empty = function(obj) {
 for(var key in obj) {
  return false;
 }
 return true;
 }
 var _extend = function(target,options) {
 if( typeof target !== 'object' || typeof options !== 'object' ) {
  return;
 }
 var copy ,clone, name;
 for( name in options ) {
  if(options.hasOwnProperty(name) && !target.hasOwnProperty(name)) {
  target[name] = options[name];
  }
 }
 return target;
 };
 // 自定义text转化json格式
 var parseJSON = function(text) {
 if(typeof text !== 'string') {
  return;
 }
 if( JSON && JSON.parse ) {
  return JSON.parse(text);
 }
 return (new Function('return '+text))();
 }
 // jsonp处理函数
 function _sendJsonpRequest(url,callbackName,succCallback) {
 var script = document.createElement('script');
 script.type="text/javascript";
 script.src=url;
 document.body.appendChild(script);
 // 如果用户自己定义了回调函数,就用自己定义的,否则,调用success函数
 window[callbackName] = window[callbackName] || succCallback;
 }
 return function (options) {
 // 没有传参或者没有url,抛出错误
 if( !options || !options.url ) {
  throw('参数错误!');
 }
 // 继承操作
 options.type = options.type.toUpperCase();
 _extend(options,_options);
 /*jsonp部分,直接返回*/
 if( options.dataType === 'jsonp' ) {
  var jsonpUrl = options.url.indexOf('?') > -1 ? options.url: options.url +
  '?' + options.jsonp+ '=' + options.jsonpCallback;
  _sendJsonpRequest(jsonpUrl,options.jsonpCallback,options.success);
  return;
 }
  //XMLHttpRequest传参无影响
 var xhr = new (window.XMLHttpRequest || ActiveXObject)('Microsoft.XMLHTTP');
 // get搜索字符串
 var search = '';
 // 将data序列化
 var param= _param(options.data)
 if( options.type === 'GET' ) {
  search = (options.url.indexOf('?') > -1 ? '&' : '?') + param;
  if(!options.cache) {
  search += '&radom='+Math.random();
  }
  param = null;
 }
 xhr.open( options.type, options.url + search, options.async );
 xhr.onreadystatechange = function() {
  if( xhr.readyState == 4 ) {
  if( xhr.status >= 200 && xhr.status < 300 || xhr.status == 304 ) {
   var text = xhr.responseText;
   // json格式转换
   if(options.dataType == 'json') {
    text = parseJSON(text)
   }
   if( typeof options.success === 'function') {
   options.success(text,xhr.status)
   }
  }else {
   if(typeof options.fail === 'function') {
   options.fail('获取失败', 500)
   }
  }
  }
 }
 xhr.setRequestHeader('content-type',options.contentType);
 // get请求时param时null
 xhr.send(param);
 // 如果设置了超时,就定义
 if(typeof options.timeout === 'number') {
  // ie9+
  if( xhr.timeout ) {
  xhr.timeout = options.timeout;
  }else {
  setTimeout(function() {
   xhr.abort();
  },options.timeout)
  }
 }
 }
}()

可以看到,我们很熟悉的xhr代码,在这里,我们需要写一个解析返回字串形成json格式对象的方法parseJSON,类似于jq中的parseJSON方法,如上所示。

我们还需要设置超时代码,如果设置了请求超时,我们就如上定义。

注意:上面代码中,由于懒,设置请求头一行并没有判断是否在post请求下,你可以自己设置~~~。

结尾

一个简单的ajax方法就完成了,你是否也完成了呢?如果你懂deferred,你可以尝试着书写为deferred格式,很简单的~~~。

以上所述是小编给大家介绍的jQuery ajax的功能实现方法详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
Javascript实例教程(19) 使用HoTMetal(1)
Dec 23 Javascript
juqery 学习之六 CSS--css、位置、宽高
Feb 11 Javascript
JavaScript中的异常捕捉介绍
Dec 31 Javascript
学习vue.js条件渲染
Dec 03 Javascript
angular双向绑定模拟探索
Dec 26 Javascript
Vue监听数组变化源码解析
Mar 09 Javascript
jQuery实现的页面遮罩层功能示例【测试可用】
Oct 14 jQuery
BootStrap TreeView使用实例详解
Nov 01 Javascript
父组件中vuex方法更新state子组件不能及时更新并渲染的完美解决方法
Apr 25 Javascript
微信小程序实现定位及到指定位置导航的示例代码
Aug 20 Javascript
vuex刷新后数据丢失的解决方法
Oct 18 Javascript
JavaScript ES6的函数拓展
Jan 18 Javascript
详解JS中定时器setInterval和setTImeout的this指向问题
Jan 06 #Javascript
Jqprint实现页面打印
Jan 06 #Javascript
JS使用正则截取两个字符串之间的字符串实现方法详解
Jan 06 #Javascript
jQuery EasyUi 验证功能实例解析
Jan 06 #Javascript
jQuery编写网页版2048小游戏
Jan 06 #Javascript
利用JQuery实现datatables插件的增加和删除行功能
Jan 06 #Javascript
javascript正则表达式模糊匹配IP地址功能示例
Jan 06 #Javascript
You might like
一个查看session内容的函数
2006/10/09 PHP
php删除左端与右端空格的方法
2014/11/29 PHP
Symfony2实现在doctrine中内置数据的方法
2016/02/05 PHP
ajax调用返回php接口返回json数据的方法(必看篇)
2017/05/05 PHP
ExtJs GridPanel简单的增删改实现代码
2010/08/26 Javascript
JavaScript表达式:URL 协议介绍
2013/03/10 Javascript
用JavaScript实现动画效果的方法
2013/07/20 Javascript
javascript使用switch case实现动态改变超级链接文字及地址
2014/12/16 Javascript
javascript正则表达式基础知识入门
2015/04/20 Javascript
原生javascript实现解析XML文档与字符串
2016/03/01 Javascript
jQuery Easyui学习教程之实现datagrid在没有数据时显示相关提示内容
2016/07/09 Javascript
浅谈js常用内置方法和对象
2016/09/24 Javascript
[原创]jquery判断元素内容是否为空的方法
2018/05/04 jQuery
vue监听input标签的value值方法
2018/08/27 Javascript
解决vue中监听input只能输入数字及英文或者其他情况的问题
2018/08/30 Javascript
vue插槽slot的理解和使用方法
2019/04/03 Javascript
JS前端知识点总结之内置对象,日期对象和定时器相关操作
2019/07/05 Javascript
vue+elementUI实现图片上传功能
2019/08/20 Javascript
layui表格内放置图片,并点击放大的实例
2019/09/10 Javascript
Python中enumerate()函数编写更Pythonic的循环
2018/03/06 Python
Python判断一个list中是否包含另一个list全部元素的方法分析
2018/12/24 Python
selenium跳过webdriver检测并模拟登录淘宝
2019/06/12 Python
机器学习实战之knn算法pandas
2019/06/22 Python
Python发送邮件的实例代码讲解
2019/10/16 Python
如何使用 Python 读取文件和照片的创建日期
2020/09/05 Python
CSS3媒体查询Media Queries基础学习教程
2016/02/29 HTML / CSS
使用CSS3 制作一个material-design 风格登录界面实例
2016/12/12 HTML / CSS
美国网上眼镜商城:Zenni Optical
2016/11/20 全球购物
女孩每月服装订阅盒:kidpik
2019/04/17 全球购物
西雅图电动自行车公司:Rad Power Bikes
2020/02/02 全球购物
init进程的作用
2012/04/12 面试题
宣传口号大全
2014/06/16 职场文书
党员三严三实心得体会
2014/10/13 职场文书
2016教师节感恩话语
2015/12/09 职场文书
2016拓展训练心得体会范文
2016/01/12 职场文书
【js设计模式】SOLID五大设计原则
2022/03/24 Javascript