由于jQuery中的Ajax方法是用了内置的deferred模块,是Promise模式的一种实现,而我们这里没有讲过,所以我们就不使用这一模式啦。
我们只定义一个Ajax方法,他可以简单的get,post,jsonp请求就可以了。
一、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的回调函数名,第三个是成功回调函数,我们在这个函数内建立一个src为jsonpUrl的script元素插入到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构造函数传递参数是无影响,然后我们定义了两个辅助变量:search、param,前者用于get请求的查询字串,后者用于post请求的send内容,我们定义了一个_param方法来讲对象转换为send方法参数的模式,就如你看到的那样,下面我们做了get与post之间合理的search、param的赋值工作。接下来我们就可以发送请求书写最激动人心的内容了。
最终的代码如下
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请求下,你可以自己设置