AJAX
☎ get 请求
var xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else if (window.ActiveXObjext) {
xhr = new ActiveXObject("Microsoft.XMLHttp");
}
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
var result = xhr.responseText;
}
}
xhr.open("get", url, boolean);
xhr.send();
☎ post 请求
var xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else if (window.ActiveXObjext) {
xhr = new ActiveXObject("Microsoft.XMLHttp");
}
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
xhr.responseText
}
}
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.open("post", url);
xhr.send(data);
全平台兼容
function getXHR(){
var xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) {
try {
xhr = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
alert("您的浏览器暂不支持 Ajax!");
}
}
}
return xhr;
}
封装 AJAX(仿jQuery)
var ajax = {
get: function(url, data, callback) {
var str = "";
if (typeof data === "string") {
str = data;
} else if (typeof data === "object") {
for (var i in data) {
str += i + "=" + data[i] + "&";
}
str = str.slice(0, -1);
}
var xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else if (window.ActiveXObjext) {
xhr = new ActiveXObject("Microsoft.XMLHttp");
}
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
var text = ajax.responseText;
var obj = (new Function("return " + text))();
callback(obj);
}
}
xhr.open("get", url + "?" + str, true);
xhr.send();
},
post: function(url, data, callback) {
var str = "";
if (typeof data === "string") {
str = data;
} else if (typeof data === "object") {
for (var i in data) {
str += i + "=" + data[i] + "&";
}
str = str.slice(0, -1);
}
var xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) {
xhr = new ActiveXObject("Microsoft.XMLHttp");
}
ajax.onreadystatechange = function() {
if (xhr.readyState === 4) {
var text = ajax.responseText;
var obj = (new Function("return " + text))();
callback(obj);
}
}
xhr.open("post", url, true);
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
xhr.send(str);
}
};
浏览器线程机制
✚ 渲染线程
✚ javascript 引擎线程
✚ 浏览器事件触发线程
✚ HTTP 请求线程
通常,线程间的交互以事件的方式发生,通过事件回调的方式予以通知
而事件回调又是以先进先出的方式添加到任务队列的末尾,等到 js 引擎空闲时,
任务队列中排队的任务将会依次被执行
这些事件回调包括 setTimeout、setInterval、click、ajax 异步请求等回调
在浏览器中 js 引擎线程会循环从任务队列中读取事件并且执行,这种运行机制称
作 Event Loop (事件循环)
AJAX 执行流程
对于一个 ajax 请求,js 引擎首先生成 XMLHttpRequest 实例对象,调用
open() 方法后再调用 send() 方法,至此所有的语句都是同步执行
但从 send() 方法内部开始,浏览器为将要发生的网络请求创建了新的 http
请求线程,这个线程独立于 js 引擎线程,于是网络请求异步被发送出去了
当 ajax 请求被服务器响应并且收到 response 后,浏览器事件触发线程捕获到
了 ajax 的回调事件;该回调事件并没有被立即执行,而是被添加到任务队列的末
尾,直到 js 引擎空闲时任务队列的任务才被捞出来,按照添加顺序挨个执行
在 onreadystatechange 事件内部,有可能对 dom 进行操作;此时浏览器便
会挂起 js 引擎线程,转而执行 GUI 渲染线程,进行重绘或者回流
当 js 引擎重新执行时,GUI 渲染线程又会被挂起,GUI 更新将被保存起来等
到 js 引擎空闲时立即被执行
XMLHttpRequest 实例对象属性方法解读
☎ readyState 属性
只读属性,readyState 属性记录了 ajax 调用过程中所有可能的状态
☎ onreadystatechange 事件
onreadystatechange 事件回调函数在 readystate 状态改变时触发
在一个收到响应的 ajax 请求周期中,onreadystatechange 方法会被触发 4 次.
☎ status 属性
只读属性,status 表示 http 请求的状态,初始值为 0
如果服务器没有显式地指定状态码,那么 status 将被设置为默认值(200)
☎ statusText 属性
只读属性,statusText 表示服务器的响应状态信息,为一个 UTF-16 的字符串
当 status 为 20X 的时候返回大写的 OK,请求失败的时候返回空字符串
其他情况下返回相应的状态描述
☎ onloadstart 事件
onloadstart 事件回调函数在 ajax 请求发送之前触发
触发时机在 readyState == 1 状态之后,readyState == 2 状态之前
默认传入一个 ProgressEvent 事件进度对象
☎ onprogress 事件
onprogress 事件回调函数在 readyState == 3 状态时开始触发,默认传入 ProgressEvent 对象
可以通过 e.loaded / e.total 来计算加载资源的进度
注意:该方法适用于 IE10+ 及其他现代浏览器
☎ onload 事件
onload 事件回调函数在 ajax 请求成功后触发
触发时机在 readyState == 4 状态之后
xhr.onload = function() {
var status = xhr.status;
if ((status >= 200 && status < 300) || status == 304) {
var resp = xhr.responseText;
}
}
☎ onloadend 事件
onloadend 事件回调函数在 ajax 请求完成后触发
触发时机在 readyState == 4 状态之后(收到响应时)
或者 readyState == 2 状态之后(未收到响应时)
默认将传入一个 ProgressEvent 事件进度对象
☎ timeout 属性
timeout 属性用于指定 ajax 的超时时长
✚ 设置为 0 时不生效
✚ 设置为字符串时,如果字符串中全部为数字会自动将字符串
转化为数字,反之该设置不生效
✚ 设置为对象时,如果该对象能够转化为数字,那么将设置为
转化后的数字
☎ ontimeout 事件
ontimeout 事件回调函数在 ajax 请求超时时触发,可以在 ajax
请求超时时做一些后续处理
☎ response 和 responseText 属性
response 表示服务器的响应内容
responseText 表示服务器响应内容的文本形式
response 和 responseText 均为只读属性
☎ responseXML 属性
只读属性,responseXML 表示 xml 形式的响应数据,缺省为 null
若数据不是有效的 xml 则会报错
☎ responseType 属性
responseType 表示响应的类型,缺省为空字符串
可取 "arraybuffer"、"blob"、"document"、"json" 和 "text" 共五种类型
☎ responseURL 属性
responseURL 返回 ajax 请求最终的 URL
如果请求中存在重定向,那么 responseURL 表示重定向之后的 URL
☎ withCredentials 属性
withCredentials 是一个布尔值,默认为false
表示跨域请求中不发送 cookies 等信息
注意:该属性适用于 IE10+, opera12+ 及其他现代浏览器
☎ abort() 方法
abort() 方法用于取消 ajax 请求;取消后 readyState 状态将被设置为 0
☎ getResponseHeader("name") 方法
getResponseHeader("name") 方法用于获取 ajax 响应头中指定 name 的值
如果 response headers 中存在相同的 name,那么将自动以字符串的形式连接在一起
readyState === 2 状态时,就意味着响应头已接受完整
☎ getAllResponseHeaders() 方法
getAllResponseHeaders() 方法用于获取所有安全的 ajax 响应头,响应头以字符串形式返回
readyState === 2 状态时,就意味着响应头已接受完整
☎ setRequestHeader("key", "value") 方法
获取响应头
☎ onerror 事件
onerror 事件回调函数用于在 ajax 请求出错后执行
☎ upload 属性
upload 属性默认返回一个 XMLHttpRequestUpload 对象,用于上传资源
对象事件方法
onloadstart onprogress onabort onerror
onload ontimeout onloadend
☎ overrideMimeType("key", "value")
overrideMimeType 方法用于强制指定 response 的 MIME 类型