UDN-企业互联网技术人气社区

板块导航

浏览  : 769
回复  : 2

[jQuery] jQuery之ajax实现篇

[复制链接]
葡萄柚的头像 楼主
发表于 2017-2-5 10:12:23 | 显示全部楼层 |阅读模式
  jQuery的ajax方法非常好用,这么好的东西,你想拥有一个属于自己的ajax么?接下来,我们来自己做一个简单的ajax吧。

  实现功能

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

  我们只定义一个ajax方法,他可以简单的get,post,jsonp请求就可以啦~~
  1. var ajax = function () {
  2.    
  3.   //  做一些初始化,定义一些私有函数等

  4.   return function () {
  5.     // ajax主体代码
  6.   }
  7.    
  8. }()


  9. ajax({
  10.   url: myUrl,
  11.   type: 'get',
  12.   dataType: 'json',
  13.   timeout: 1000,
  14.   success: function (data, status) {
  15.     console.log(data)
  16.   },
  17.   fail: function (err, status) {
  18.     console.log(err)
  19.   }
  20. })
复制代码

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

  整体思路

  我们的ajax方法需要传递一个对象进去,这个对象中我们可以定义一些我们希望的属性,我们就必须初始一下各种属性
  1. //默认请求参数
  2.   var _options = {
  3.     url: null,  // 请求连接
  4.     type: 'GET',  // 请求类型
  5.     data: null,  // post时请求体
  6.     dataType: 'text',  // 返回请求的类型,有text/json两种
  7.     jsonp: 'callback',  // jsonp请求的标志,一般不改动
  8.     jsonpCallback: 'jsonpCallback',  //jsonp请求的函数名
  9.     async: true,   // 是否异步
  10.     cache: true,   // 是否缓存
  11.     timeout:null,  // 设置请求超时
  12.     contentType: 'application/x-www-form-urlencoded',
  13.     success: null,  // 请求成功回调函数
  14.     fail: null   // 请求失败回调
  15.   }
复制代码

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

  2.   //默认请求参数
  3.   var _options = {
  4.     url: null,
  5.     type: 'GET',
  6.     data: null,
  7.     dataType: 'text',
  8.     jsonp: 'callback',
  9.     jsonpCallback: 'jsonpCallback',
  10.     async: true,
  11.     cache: true,
  12.     timeout:null,
  13.     contentType: 'application/x-www-form-urlencoded',
  14.     success: null,
  15.     fail: null
  16.   }
  17.   // ...
  18.   return function (options) {
  19.      // ...
  20.   }
  21. }()
复制代码

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

  2.   //默认请求参数
  3.   var _options = {
  4.     url: null,
  5.     type: 'GET',
  6.     data: null,
  7.     dataType: 'text',
  8.     jsonp: 'callback',
  9.     jsonpCallback: 'jsonpCallback',
  10.     async: true,
  11.     cache: true,
  12.     timeout:null,
  13.     contentType: 'application/x-www-form-urlencoded',
  14.     success: null,
  15.     fail: null
  16.   }
  17.   //  内部使用的继承方法
  18.   var _extend = function(target,options) {
  19.     if( typeof target !== 'object' || typeof options !== 'object' ) {
  20.       return;
  21.     }
  22.     var copy ,clone, name;
  23.     for( name in options ) {
  24.       if(options.hasOwnProperty(name) && !target.hasOwnProperty(name)) {
  25.         target[name] = options[name];
  26.       }
  27.     }
  28.     return target;
  29.   };


  30.   // ...
  31.   return function (options) {

  32.     // 没有传参或者没有url,抛出错误
  33.     if( !options || !options.url ) {
  34.       throw('参数错误!');
  35.     }

  36.     // 继承操作
  37.     options.type = options.type.toUpperCase();
  38.     _extend(options,_options);
  39.      // ...
  40.   }
  41. }()
复制代码

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

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

  2.   //默认请求参数
  3.   var _options = {
  4.     url: null,
  5.     type: 'GET',
  6.     data: null,
  7.     dataType: 'text',
  8.     jsonp: 'callback',
  9.     jsonpCallback: 'jsonpCallback',
  10.     async: true,
  11.     cache: true,
  12.     timeout:null,
  13.     contentType: 'application/x-www-form-urlencoded',
  14.     success: null,
  15.     fail: null
  16.   }
  17.   //  内部使用的继承方法
  18.   var _extend = function(target,options) {
  19.     if( typeof target !== 'object' || typeof options !== 'object' ) {
  20.       return;
  21.     }
  22.     var copy ,clone, name;
  23.     for( name in options ) {
  24.       if(options.hasOwnProperty(name) && !target.hasOwnProperty(name)) {
  25.         target[name] = options[name];
  26.       }
  27.     }
  28.     return target;
  29.   };
  30.   
  31.   // jsonp处理函数
  32.   function _sendJsonpRequest(url,callbackName,succCallback) {

  33.     var script = document.createElement('script');

  34.     script.type="text/JavaScript";
  35.     script.src=url;

  36.     document.body.appendChild(script);
  37.     // 如果用户自己定义了回调函数,就用自己定义的,否则,调用success函数
  38.     window[callbackName] = window[callbackName] || succCallback;

  39.   }

  40.   // ...
  41.   return function (options) {

  42.     // 没有传参或者没有url,抛出错误
  43.     if( !options || !options.url ) {
  44.       throw('参数错误!');
  45.     }

  46.     // 继承操作
  47.     options.type = options.type.toUpperCase();
  48.     _extend(options,_options);

  49.     /*jsonp部分,直接返回*/
  50.     if( options.dataType === 'jsonp' ) {
  51.       var jsonpUrl = options.url.indexOf('?') > -1 ? options.url: options.url +
  52.         '?' + options.jsonp+ '=' + options.jsonpCallback;

  53.      return  _sendJsonpRequest(jsonpUrl,options.jsonpCallback,options.success);
  54.       
  55.     }
  56.      // ...
  57.   }
  58. }()
复制代码

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

  好,处理好jsonp请求后,我们开始处理xhr请求了。
  1. var ajax = function () {

  2.   //默认请求参数
  3.   var _options = {
  4.     url: null,
  5.     type: 'GET',
  6.     data: null,
  7.     dataType: 'text',
  8.     jsonp: 'callback',
  9.     jsonpCallback: 'jsonpCallback',
  10.     async: true,
  11.     cache: true,
  12.     timeout:null,
  13.     contentType: 'application/x-www-form-urlencoded',
  14.     success: null,
  15.     fail: null
  16.   }
  17.   //  内部使用的继承方法
  18.   var _extend = function(target,options) {
  19.     if( typeof target !== 'object' || typeof options !== 'object' ) {
  20.       return;
  21.     }
  22.     var copy ,clone, name;
  23.     for( name in options ) {
  24.       if(options.hasOwnProperty(name) && !target.hasOwnProperty(name)) {
  25.         target[name] = options[name];
  26.       }
  27.     }
  28.     return target;
  29.   };
  30.   
  31.   // jsonp处理函数
  32.   function _sendJsonpRequest(url,callbackName,succCallback) {

  33.     var script = document.createElement('script');

  34.     script.type="text/JavaScript";
  35.     script.src=url;

  36.     document.body.appendChild(script);
  37.     // 如果用户自己定义了回调函数,就用自己定义的,否则,调用success函数
  38.     window[callbackName] = window[callbackName] || succCallback;

  39.   }
  40.   
  41.   // json转化为字符串
  42.   var _param = function(data) {
  43.     var str = '';
  44.     if( !data || _empty(data)) {
  45.       return str;
  46.     }
  47.     for(var key in data) {
  48.       str += key + '='+ data[key]+'&'
  49.     }
  50.     str = str.slice(0,-1);
  51.     return str;
  52.   }
  53.   //判断对象是否为空
  54.   var _empty = function(obj) {
  55.     for(var key in obj) {
  56.       return false;
  57.     }
  58.     return true;
  59.   }

  60.   // ...
  61.   return function (options) {

  62.     // 没有传参或者没有url,抛出错误
  63.     if( !options || !options.url ) {
  64.       throw('参数错误!');
  65.     }

  66.     // 继承操作
  67.     options.type = options.type.toUpperCase();
  68.     _extend(options,_options);

  69.     /*jsonp部分,直接返回*/
  70.     if( options.dataType === 'jsonp' ) {
  71.       var jsonpUrl = options.url.indexOf('?') > -1 ? options.url: options.url +
  72.         '?' + options.jsonp+ '=' + options.jsonpCallback;

  73.      return  _sendJsonpRequest(jsonpUrl,options.jsonpCallback,options.success);
  74.       
  75.     }
  76.    
  77.      //XMLHttpRequest传参无影响
  78.     var xhr = new (window.XMLHttpRequest || ActiveXObject)('Microsoft.XMLHTTP');
  79.     // get搜索字符串
  80.     var search = '';

  81.     // 将data序列化
  82.     var param= _param(options.data)

  83.     if( options.type === 'GET' ) {
  84.       search = (options.url.indexOf('?') > -1 ? '&' : '?') + param;
  85.       if(!options.cache) {
  86.         search += '&radom='+Math.random();
  87.       }
  88.       
  89.       param = null;
  90.     }

  91.      // ...
  92.   }
  93. }()
复制代码

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

  最终的代码如下
  1. ;

  2. var ajax = function () {

  3.   //默认请求参数
  4.   var _options = {
  5.     url: null,
  6.     type: 'GET',
  7.     data: null,
  8.     dataType: 'text',
  9.     jsonp: 'callback',
  10.     jsonpCallback: 'jsonpCallback',
  11.     async: true,
  12.     cache: true,
  13.     timeout:null,
  14.     contentType: 'application/x-www-form-urlencoded',
  15.     success: null,
  16.     fail: null
  17.   }


  18.   // json转化为字符串
  19.   var _param = function(data) {
  20.     var str = '';
  21.     if( !data || _empty(data)) {
  22.       return str;
  23.     }
  24.     for(var key in data) {
  25.       str += key + '='+ data[key]+'&'
  26.     }
  27.     str = str.slice(0,-1);
  28.     return str;
  29.   }
  30.   //判断对象是否为空
  31.   var _empty = function(obj) {
  32.     for(var key in obj) {
  33.       return false;
  34.     }
  35.     return true;
  36.   }

  37.   var _extend = function(target,options) {
  38.     if( typeof target !== 'object' || typeof options !== 'object' ) {
  39.       return;
  40.     }
  41.     var copy ,clone, name;
  42.     for( name in options ) {
  43.       if(options.hasOwnProperty(name) && !target.hasOwnProperty(name)) {
  44.         target[name] = options[name];
  45.       }
  46.     }
  47.     return target;
  48.   };

  49.   // 自定义text转化json格式
  50.   var parseJSON = function(text) {
  51.     if(typeof text !== 'string') {
  52.       return;
  53.     }
  54.     if( JSON && JSON.parse ) {
  55.       return JSON.parse(text);
  56.     }
  57.     return (new Function('return '+text))();
  58.   }

  59.   // jsonp处理函数
  60.   function _sendJsonpRequest(url,callbackName,succCallback) {

  61.     var script = document.createElement('script');

  62.     script.type="text/JavaScript";
  63.     script.src=url;

  64.     document.body.appendChild(script);
  65.     // 如果用户自己定义了回调函数,就用自己定义的,否则,调用success函数
  66.     window[callbackName] = window[callbackName] || succCallback;

  67.   }


  68.   return function (options) {

  69.     // 没有传参或者没有url,抛出错误
  70.     if( !options || !options.url ) {
  71.       throw('参数错误!');
  72.     }

  73.     // 继承操作
  74.     options.type = options.type.toUpperCase();
  75.     _extend(options,_options);

  76.     /*jsonp部分,直接返回*/
  77.     if( options.dataType === 'jsonp' ) {
  78.       var jsonpUrl = options.url.indexOf('?') > -1 ? options.url: options.url +
  79.         '?' + options.jsonp+ '=' + options.jsonpCallback;

  80.       _sendJsonpRequest(jsonpUrl,options.jsonpCallback,options.success);
  81.       
  82.       return;
  83.     }

  84.      //XMLHttpRequest传参无影响
  85.     var xhr = new (window.XMLHttpRequest || ActiveXObject)('Microsoft.XMLHTTP');

  86.     // get搜索字符串
  87.     var search = '';

  88.     // 将data序列化
  89.     var param= _param(options.data)

  90.     if( options.type === 'GET' ) {
  91.       search = (options.url.indexOf('?') > -1 ? '&' : '?') + param;
  92.       if(!options.cache) {
  93.         search += '&radom='+Math.random();
  94.       }
  95.       
  96.       param = null;
  97.     }

  98.     xhr.open( options.type, options.url + search, options.async );

  99.     xhr.onreadystatechange = function() {
  100.       if( xhr.readyState == 4 ) {
  101.         if( xhr.status >= 200 && xhr.status < 300 || xhr.status == 304 ) {
  102.           var text = xhr.responseText;
  103.           // json格式转换
  104.           if(options.dataType == 'json') {
  105.               text = parseJSON(text)
  106.           }

  107.           if( typeof options.success === 'function') {

  108.             options.success(text,xhr.status)
  109.           }
  110.          
  111.         }else {

  112.           if(typeof options.fail === 'function') {
  113.             options.fail('获取失败', 500)
  114.           }
  115.          
  116.         }
  117.       }
  118.     }

  119.     xhr.setRequestHeader('content-type',options.contentType);
  120.     // get请求时param时null
  121.     xhr.send(param);

  122.     // 如果设置了超时,就定义
  123.     if(typeof options.timeout === 'number') {
  124.       // ie9+
  125.       if( xhr.timeout ) {
  126.         xhr.timeout = options.timeout;
  127.       }else {
  128.         setTimeout(function() {
  129.           xhr.abort();
  130.         },options.timeout)
  131.       }
  132.     }
  133.   }

  134. }()
复制代码

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

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

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

  结尾

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

相关帖子

发表于 2017-2-5 10:12:52 | 显示全部楼层
貌似看过类似的文章恩,排版更清晰点就更好了
使用道具 举报

回复

发表于 2017-2-11 16:16:56 | 显示全部楼层
JavaScript依赖于浏览器本身,与操作环境无关,只要计算机能运行浏览器,并支持JavaScript的浏览器,就可正确执行,从而实现了“编写一次,走遍天下”的梦想。
使用道具 举报

回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部