第111天:Ajax之jQuery实现方法

Posted 半指温柔乐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第111天:Ajax之jQuery实现方法相关的知识,希望对你有一定的参考价值。

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

我们只定义一个Ajax方法,他可以简单的getpostjsonp请求就可以了。

一、jQuery语法格式

 1 var ajax = function () {
 2     
 3   //  做一些初始化,定义一些私有函数等
 4  
 5   return function () {
 6     // ajax主体代码
 7   }
 8     
 9 }()
10 
11 
12 ajax({
13   url: myUrl,
14   type: ‘get,
15   dataType: ‘json,
16   timeout: 1000,
17   success: function (data, status) {
18     console.log(data)
19   },
20   fail: function (err, status) {
21     console.log(err)
22   }
23 })

二、初始化属性

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主体函数的书写,现在的Ajax方法是这样了

 1 var ajax = function () {
 2 
 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   // ...
19   return function (options) {
20      // ...
21   }
22 }()

四、内部继承

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

 1 var ajax = function () {
 2 
 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   //  内部使用的继承方法
19   var _extend = function(target,options) {
20     if( typeof target !== ‘object‘ || typeof options !== ‘object‘ ) {
21       return;
22     }
23     var copy ,clone, name;
24     for( name in options ) {
25       if(options.hasOwnProperty(name) && !target.hasOwnProperty(name)) {
26         target[name] = options[name];
27       }
28     }
29     return target;
30   };
31 
32 
33   // ...
34   return function (options) {
35 
36     // 没有传参或者没有url,抛出错误
37     if( !options || !options.url ) {
38       throw(‘参数错误!‘);
39     }
40 
41     // 继承操作
42     options.type = options.type.toUpperCase();
43     _extend(options,_options);
44      // ...
45   }
46 }()

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

五、jsonp请求

jsonp请求不是xhr请求,他是将请求url当做script标签的src值插入到页面body中去实现的,我们先把jsonp请求处理一下再开始建立xhr请求的代码吧。

 1 var ajax = function () {
 2 
 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   //  内部使用的继承方法
19   var _extend = function(target,options) {
20     if( typeof target !== ‘object‘ || typeof options !== ‘object‘ ) {
21       return;
22     }
23     var copy ,clone, name;
24     for( name in options ) {
25       if(options.hasOwnProperty(name) && !target.hasOwnProperty(name)) {
26         target[name] = options[name];
27       }
28     }
29     return target;
30   };
31   
32   // jsonp处理函数
33   function _sendJsonpRequest(url,callbackName,succCallback) {
34 
35     var script = document.createElement(‘script‘);
36 
37     script.type="text/javascript";
38     script.src=url;
39 
40     document.body.appendChild(script);
41     // 如果用户自己定义了回调函数,就用自己定义的,否则,调用success函数
42     window[callbackName] = window[callbackName] || succCallback;
43 
44   }
45 
46   // ...
47   return function (options) {
48 
49     // 没有传参或者没有url,抛出错误
50     if( !options || !options.url ) {
51       throw(‘参数错误!‘);
52     }
53 
54     // 继承操作
55     options.type = options.type.toUpperCase();
56     _extend(options,_options);
57 
58     /*jsonp部分,直接返回*/
59     if( options.dataType === ‘jsonp‘ ) {
60       var jsonpUrl = options.url.indexOf(‘?‘) > -1 ? options.url: options.url +
61         ‘?‘ + options.jsonp+ ‘=‘ + options.jsonpCallback;
62 
63      return  _sendJsonpRequest(jsonpUrl,options.jsonpCallback,options.success);
64       
65     }
66      // ...
67   }
68 }()

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

六、xhr请求处理

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

  1 var ajax = function () {
  2 
  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   //  内部使用的继承方法
 19   var _extend = function(target,options) {
 20     if( typeof target !== ‘object‘ || typeof options !== ‘object‘ ) {
 21       return;
 22     }
 23     var copy ,clone, name;
 24     for( name in options ) {
 25       if(options.hasOwnProperty(name) && !target.hasOwnProperty(name)) {
 26         target[name] = options[name];
 27       }
 28     }
 29     return target;
 30   };
 31   
 32   // jsonp处理函数
 33   function _sendJsonpRequest(url,callbackName,succCallback) {
 34 
 35     var script = document.createElement(‘script‘);
 36 
 37     script.type="text/javascript";
 38     script.src=url;
 39 
 40     document.body.appendChild(script);
 41     // 如果用户自己定义了回调函数,就用自己定义的,否则,调用success函数
 42     window[callbackName] = window[callbackName] || succCallback;
 43 
 44   }
 45   
 46   // json转化为字符串
 47   var _param = function(data) {
 48     var str = ‘‘;
 49     if( !data || _empty(data)) {
 50       return str;
 51     }
 52     for(var key in data) {
 53       str += key + ‘=‘+ data[key]+‘&‘
 54     }
 55     str = str.slice(0,-1);
 56     return str;
 57   }
 58   //判断对象是否为空
 59   var _empty = function(obj) {
 60     for(var key in obj) {
 61       return false;
 62     }
 63     return true;
 64   }
 65 
 66   // ...
 67   return function (options) {
 68 
 69     // 没有传参或者没有url,抛出错误
 70     if( !options || !options.url ) {
 71       throw(‘参数错误!‘);
 72     }
 73 
 74     // 继承操作
 75     options.type = options.type.toUpperCase();
 76     _extend(options,_options);
 77 
 78     /*jsonp部分,直接返回*/
 79     if( options.dataType === ‘jsonp‘ ) {
 80       var jsonpUrl = options.url.indexOf(‘?‘) > -1 ? options.url: options.url +
 81         ‘?‘ + options.jsonp+ ‘=‘ + options.jsonpCallback;
 82 
 83      return  _sendJsonpRequest(jsonpUrl,options.jsonpCallback,options.success);
 84       
 85     }
 86     
 87      //XMLHttpRequest传参无影响
 88     var xhr = new (window.XMLHttpRequest || ActiveXObject)(‘Microsoft.XMLHTTP‘);
 89     // get搜索字符串
 90     var search = ‘‘;
 91 
 92     // 将data序列化
 93     var param= _param(options.data)
 94 
 95     if( options.type === ‘GET‘ ) {
 96       search = (options.url.indexOf(‘?‘) > -1 ? ‘&‘ : ‘?‘) + param;
 97       if(!options.cache) {
 98         search += ‘&radom=‘+Math.random();
 99       }
100       
101       param = null;
102     }
103 
104      // ...
105   }
106 }()

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

最终的代码如下

  1 ;
  2 
  3 var ajax = function () {
  4 
  5   //默认请求参数
  6   var _options = {
  7     url: null,
  8     type: ‘GET‘,
  9     data: null,
 10     dataType: ‘text‘,
 11     jsonp: ‘callback‘,
 12     jsonpCallback: ‘jsonpCallback‘,
 13     async: true,
 14     cache: true,
 15     timeout:null,
 16     contentType: ‘application/x-www-form-urlencoded‘,
 17     success: null,
 18     fail: null
 19   }
 20 
 21 
 22   // json转化为字符串
 23   var _param = function(data) {
 24     var str = ‘‘;
 25     if( !data || _empty(data)) {
 26       return str;
 27     }
 28     for(var key in data) {
 29       str += key + ‘=‘+ data[key]+‘&‘
 30     }
 31     str = str.slice(0,-1);
 32     return str;
 33   }
 34   //判断对象是否为空
 35   var _empty = function(obj) {
 36     for(var key in obj) {
 37       return false;
 38     }
 39     return true;
 40   }
 41 
 42   var _extend = function(target,options) {
 43     if( typeof target !== ‘object‘ || typeof options !== ‘object‘ ) {
 44       return;
 45     }
 46     var copy ,clone, name;
 47     for( name in options ) {
 48       if(options.hasOwnProperty(name) && !target.hasOwnProperty(name)) {
 49         target[name] = options[name];
 50       }
 51     }
 52     return target;
 53   };
 54 
 55   // 自定义text转化json格式
 56   var parseJSON = function(text) {
 57     if(typeof text !== ‘string‘) {
 58       return;
 59     }
 60     if( JSON && JSON.parse ) {
 61       return JSON.parse(text);
 62     }
 63     return (new Function(‘return ‘+text))();
 64   }
 65 
 66   // jsonp处理函数
 67   function _sendJsonpRequest(url,callbackName,succCallback) {
 68 
 69     var script = document.createElement(‘script‘);
 70 
 71     script.type="text/javascript";
 72     script.src=url;
 73 
 74     document.body.appendChild(script);
 75     // 如果用户自己定义了回调函数,就用自己定义的,否则,调用success函数
 76     window[callbackName] = window[callbackName] || succCallback;
 77 
 78   }
 79 
 80 
 81   return function (options) {
 82 
 83     // 没有传参或者没有url,抛出错误
 84     if( !options || !options.url ) {
 85       throw(‘参数错误!‘);
 86     }
 87 
 88     // 继承操作
 89     options.type = options.type.toUpperCase();
 90     _extend(options,_options);
 91 
 92     /*jsonp部分,直接返回*/
 93     if( options.dataType === ‘jsonp‘ ) {
 94       var jsonpUrl = options.url.indexOf(‘?‘) > -1 ? options.url: options.url +
 95         ‘?‘ + options.jsonp+ ‘=‘ + options.jsonpCallback;
 96 
 97       _sendJsonpRequest(jsonpUrl,options.jsonpCallback,options.success);
 98       
 99       return;
100     }
101 
102      //XMLHttpRequest传参无影响
103     var xhr = new (window.XMLHttpRequest || ActiveXObject)(‘Microsoft.XMLHTTP‘);
104 
105     // get搜索字符串
106     var search = ‘‘;
107 
108     // 将data序列化
109     var param= _param(options.data)
110 
111     if( options.type === ‘GET‘ ) {
112       search = (options.url.indexOf(‘?‘) > -1 ? ‘&‘ : ‘?‘) + param;
113       if(!options.cache) {
114         search += ‘&radom=‘+Math.random();
115       }
116       
117       param = null;
118     }
119 
120     xhr.open( options.type, options.url + search, options.async );
121 
122     xhr.onreadystatechange = function() {
123       if( xhr.readyState == 4 ) {
124         if( xhr.status >= 200 && xhr.status < 300 || xhr.status == 304 ) {
125           var text = xhr.responseText;
126           // json格式转换
127           if(options.dataType == ‘json‘) {
128               text = parseJSON(text)
129           }
130 
131           if( typeof options.success === ‘function‘) {
132 
133             options.success(text,xhr.status)
134           }
135           
136         }else {
137 
138           if(typeof options.fail === ‘function‘) {
139             options.fail(‘获取失败‘, 500)
140           }
141           
142         }
143       }
144     }
145 
146     xhr.setRequestHeader(‘content-type‘,options.contentType);
147     // get请求时param时null
148     xhr.send(param);
149 
150     // 如果设置了超时,就定义
151     if(typeof options.timeout === ‘number‘) {
152       // ie9+
153       if( xhr.timeout ) {
154         xhr.timeout = options.timeout;
155       }else {
156         setTimeout(function() {
157           xhr.abort();
158         },options.timeout)
159       }
160     }
161   }
162 
163 }()

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

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

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

以上是关于第111天:Ajax之jQuery实现方法的主要内容,如果未能解决你的问题,请参考以下文章

前端面试题之手写promise

第114天:Ajax跨域请求解决方法

Ajax_使用 jQuery 实现Ajax

几个非常实用的JQuery代码片段

jQuery高级Ajax

十条jQuery代码片段助力Web开发效率提升