原生ajax解析&封装原生ajax函数
前沿:对于此篇随笔,完是简要写了几个重要的地方,具体实现细节完在提供的源码做了笔记
<一>ajax基本要点介绍--更好的介绍ajax
1. ajax对象中new XMLHttpRequest()属性和方法列表
2. 常用事件介绍
事件 | 触发时机 |
---|---|
onreadystatechange | 当readyState的值改变时触发,除了当它从非0变成0时 |
onloadstart | 当调用send方法时会触发xhr.onloadstart,然后会触发xhr.upload.onloadstart,代表开始上传数据 |
onprogress | 上传数据过程中会触发xhr.upload.onprogress,下载数据过程中会触发xhr.onprogress,onprogress每50ms会触发一次 |
onabort | 调用abort方法后会触发 |
onerror | 当发生网络异常的时候会触发,如果上传数据的过程还未结束,此时会先触发xhr.upload.onerror,然后再触发xhr.onerror;如果上传数据的过程已经结束,此时只会触发xhr.onerror |
onload | 上传数据成功,会触发xhr.upload.onload;下载数据成功会触发xhr.onload |
ontimeout | 当服务端响应的时间超过指定的timeout时间时,会触发此事件 |
onloadend | 上传数据完成(成功或者失败)时会触发xhr.upload.onloadend;下载数据完成(成功或失败)会触发 |
3. 请求开始和结束零界点
【3.1】请求开始
xhr.onloadstart
事件触发的时候,也就是你调用xhr.send()
方法的时候。
因为xhr.open()
只是创建了一个连接,但并没有真正开始数据的传输,而xhr.send()
才是真正开始了数据的传输过程。只有调用了xhr.send()
,才会触发xhr.onloadstart
。
【3.2】请求结束
xhr.loadend
事件触发的时候
备注:
a.可以在 send()
之后再设置此xhr.timeout
,但计时起始点仍为调用xhr.send()
方法的时刻。
b.当xhr
为一个sync
同步请求时,xhr.timeout
必须置为0
,否则会抛错。原因可以参考本文的【如何发一个同步请求】一节。
4. 具体实现细节--封装ajax
function _ajax(obj){ var xhr = null; // 创建-非IE6 : IE6及其以下浏览器 if(window.XMLHttpRequest){ xhr=new XMLHttpRequest(); //针对某些特定版本的Mozillar浏览器的BUG进行修正 if(xhr.overrideMimeType) { xhr.overrideMimeType("text/xml"); } }else if(window.ActiveXObject){ var arr = ['MSXML2.XMLHTTP', 'Microsoft.XMLHTTP']; for(var i = 0; i < arr.length; i++){ try { xhr = new ActiveXObject(arr[i]); break; }catch (e){ console.log(e); } } } // 默认是异步请求 var asyc = obj.asyc || true; var type = obj.type.toUpperCase() || "GET"; var url = obj.url; var data = obj.data || {}; console.log(objToStr(data)); //选择发送请求方式 if(type === "GET"){ xhr.open(type,url+'?'+objToStr(data),asyc); xhr.send(); }else if(type === "POST"){ xhr.open(type,url,asyc); // 告诉后台传的是什么 xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); // xhr.setRequestHeader('Last-Modified', 'faqenfaAWASVaewfc'); xhr.send(objToStr(data)); } // 设置超时请求时间 xhr.timeout = 3000; // 发送异步回调函数 xhr.onreadystatechange = function () { console.log(xhr.readyState); // 测试追踪ajax处于那种状态,在正式代码中要隐藏此switch switch (xhr.readyState){ case 0: console.log('xhr对象被成功构造,open()方法还未被调用'); break; case 1: console.log('open()方法已被成功调用,send()方法还未被调用'); break; case 2: console.log('send()方法已经被调用, 响应头和响应状态已经返回'); break; case 3: console.log('响应体(response entity body)正在下载中,此状态下通过xhr.response可能已经有了响应数据'); break; case 4: console.log('整个数据传输过程结束,不管本次请求是成功还是失败'); break; } if(xhr.readyState === 4 && xhr.status === 200){ obj.success(xhr.responseText) }else { obj.error && obj.error(); } }; // 请求开始 xhr.onloadstart = function (e) { console.log(e,'start'); }; //ajax请求结束 xhr.loadend = function (e) { console.log(e,'end'); }; // 超时函数处理 xhr.ontimeout = function (e) { obj.timeout && obj.timeout(); console.log(e,'timeout'); }; // ajax请求错误处理 xhr.onerror = function (e) { obj.errorAsyc && obj.errorAsyc(); console.log(e,'error'); }; // 上传进度处理--upload用于在数据传输到服务器时收集一些传输信息,比如上传了多少字节,总共多少字节等,其里面还包含了一些事件回调 xhr.upload.onprogress = function (e) { obj.progress && obj.progress(); console.log(e,'progress'); }; console.log(xhr.getAllResponseHeaders(),'0000'); // 把对象转换成字符串 function objToStr(obj) { var arr = []; for(var key in obj){ arr.push(key+'='+obj[key]) } return arr.join('&'); } }
【封装ajax调用方式】
window.onload = function () { btn.onclick= function () { _ajax({ url:'http://localhost:8800', type:'post', asyc:true, //默认是true data:{ username:'zhange', password:'123456' }, success:function (data) { console.log(data); }, error:function () { } }); } };