AJAX = Asynchronous JavaScript and XML(異步的 JavaScript 和 XML)麦锯。
AJAX 不是新的編程語(yǔ)言,而是一種使用現(xiàn)有標(biāo)準(zhǔn)的新方法琅绅。
AJAX 最大的優(yōu)點(diǎn)是在不重新加載整個(gè)頁(yè)面的情況下扶欣,可以與服務(wù)器交換數(shù)據(jù)并更新部分網(wǎng)頁(yè)內(nèi)容。
AJAX 不需要任何瀏覽器插件千扶,但需要用戶允許JavaScript在瀏覽器上執(zhí)行料祠。
AJAX技術(shù)的核心是
XMLHTTPRequest
對(duì)象(XHR),雖然名字中有XML澎羞,但是Ajax通信與數(shù)據(jù)格式無(wú)關(guān)髓绽。
創(chuàng)建XHR對(duì)象
IE7+、Firefox妆绞、Opera顺呕、Chrome 和Safari 都支持原生的XHR 對(duì)象枫攀,使用XMLHttpRequest
構(gòu)造函數(shù)。
var xhr=new XMLHttpRequest();//高版本
那么重點(diǎn)來(lái)了株茶,我想要支持低版本的IE来涨,那得怎么使呢,不著急忌卤,有妙招
首先檢測(cè)原生XHR對(duì)象是否存在扫夜,如果存在則返回新實(shí)例。如果對(duì)象不存在驰徊,檢查ActiveX對(duì)象。若都沒有堕阔,那么棍厂,呵呵錯(cuò)誤走你!
function createXHR() {
if (typeof XMLHttpRequest != 'undefined') {
return new XMLHttpRequest(); //高版本
} else if (typeof ActiveXObject != 'undefined') { //IE低版本
if (typeof arguments.callee.activeXString != 'string') {
var versions = ['MSXML2.XMLHttp.6.0', 'MSXML2.XMLHttp.3.0', 'MSXML2.XMLHttp'],
i, len;
for (i = 0, len = versions.length; i < len; i++) {
try {
new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
} catch (ex) {
//跳過
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
} else {
throw new Error('No XHR object available');
}
}
使用XHR
在使用XHR對(duì)象時(shí)超陆,必須調(diào)用open()方法牺弹,它有三個(gè)參數(shù):要發(fā)送的請(qǐng)求類型(get、post)时呀、請(qǐng)求的URL和表示是否異步张漂。
xhr.open('get','dom.php',false);//對(duì)dom.php的get請(qǐng)求,false同步
open()方法并不會(huì)真正發(fā)送請(qǐng)求谨娜,而只是啟動(dòng)一個(gè)請(qǐng)求以備發(fā)送航攒。通過send()方法進(jìn)行發(fā)送請(qǐng)求,send()方法接受一個(gè)參數(shù)趴梢,作為請(qǐng)求主體發(fā)送的數(shù)據(jù)漠畜。如果不需要,必須填null坞靶,執(zhí)行send()方法之后憔狞,請(qǐng)求就會(huì)發(fā)送到服務(wù)器上。
xhr.send(null);//發(fā)送請(qǐng)求
只能向同一個(gè)域中使用相同端口和協(xié)議的URL發(fā)送請(qǐng)求彰阴。如果URL與啟動(dòng)請(qǐng)求的頁(yè)面有任何差別瘾敢,都會(huì)引發(fā)安全錯(cuò)誤。
當(dāng)請(qǐng)求發(fā)送到服務(wù)器端尿这,收到響應(yīng)后簇抵,響應(yīng)的數(shù)據(jù)會(huì)自動(dòng)填充XHR對(duì)象的屬性。共有四個(gè)屬性:
屬性名 | 說(shuō)明 |
---|---|
responseText | 作為響應(yīng)主體被返回的文本 |
responseXML | 如果響應(yīng)主體內(nèi)容類型是‘text/xml’或'application/xml ,則返回包含響應(yīng)數(shù)據(jù)的XML DOM文檔妻味。 |
status | 響應(yīng)的HTTP狀態(tài) |
statusText | HTTP狀態(tài)說(shuō)明 |
接受響應(yīng)之后正压,第一步檢查status屬性,以確定響應(yīng)已經(jīng)成功返回责球。一般200為成功焦履。
號(hào) | 已定義范圍 | 分類 |
---|---|---|
1xx | 100-101 | 信息提示 |
2xx | 200-206 | 成功 |
3xx | 300-305 | 重定向 |
4xx | 400-415 | 客戶端錯(cuò)誤 |
5xx | 500-505 | 服務(wù)器錯(cuò)誤 |
HTTP狀態(tài)碼 | 狀態(tài)字符串 | 說(shuō)明 |
---|---|---|
200 | ok | 服務(wù)器成功返回了頁(yè)面 |
301 | 永久轉(zhuǎn)移 | |
302 | found | 資源暫時(shí)轉(zhuǎn)移拓劝,常用于短連接轉(zhuǎn)長(zhǎng)連接 |
304 | Not Modified | 請(qǐng)求的資源沒有被修改,允許直接使用瀏覽器中緩存的版本 |
400 | Bad Request | 語(yǔ)法錯(cuò)誤導(dǎo)致服務(wù)器不識(shí)別 |
401 | Unauthorized | 請(qǐng)求需要用戶認(rèn)證 |
403 | Forbidden | 拒絕提供服務(wù)嘉裤,可能發(fā)生在用戶沒有輸入驗(yàn)證碼的情況下 |
404 | Not found | 指定的URL在服務(wù)器上找不到 |
500 | Internal Server Error | 服務(wù)器遇到意外錯(cuò)誤郑临,無(wú)法完成請(qǐng)求 |
502 | Bad Gateway | 網(wǎng)關(guān)錯(cuò)誤 |
503 | ServiceUnavaliable | 由于服務(wù)器過載或維護(hù)導(dǎo)致無(wú)法完成請(qǐng)求 |
xhr.open("get", "example.txt", false);
xhr.send(null);
if((xhr.status>=200&&xhr.status<300)||(xhr.status==304)){
alert(xhr.responseText);
}else{
alert(alert("Request was unsuccessful: " + xhr.status);
}
以上同步調(diào)用,簡(jiǎn)單屑宠,但是真正需要的是異步調(diào)用厢洞。使用異步調(diào)用的時(shí)候,需要觸發(fā)readystatechange
事件典奉,然后檢測(cè)readyState的屬性即可躺翻。
readyState值 | 狀態(tài) | 說(shuō)明 |
---|---|---|
0 | 未初始化 | 尚未調(diào)用open(方法) |
1 | 啟動(dòng) | 已經(jīng)調(diào)用open()方法,但尚未調(diào)用send()方法 |
2 | 發(fā)送 | 已經(jīng)調(diào)用send()卫玖,但尚未接受響應(yīng) |
3 | 接受 | 已經(jīng)接受到部分響應(yīng)數(shù)據(jù) |
4 | 完成 | 已經(jīng)接受到全部數(shù)據(jù)公你,而且可以使用 |
var xhr = createXHR();
xhr.onreadystatechange = function() {
if (readyState === 4) {//異步監(jiān)控
if ((xhr.status >= 200 && xhr.status < 300) || (xhr.status == 304)) {
alert(xhr.responseText);
} else {
alert(alert("Request was unsuccessful: " + xhr.status);
}
}
};
xhr.open("get", "example.txt", true);//異步
xhr.send(null);
使用abort()方法可以取消異步請(qǐng)求,放在send()方法之前會(huì)報(bào)錯(cuò)假瞬。放在responseText
之前會(huì)得到一個(gè)空值陕靠。
get與post
首先來(lái)了解一下http頭部信息,包含服務(wù)器返回的響應(yīng)頭信息和客戶端發(fā)送出去的請(qǐng)求頭信息脱茉。我們可以獲取響應(yīng)頭信息或者設(shè)置 請(qǐng)求頭信息剪芥。
名稱 | 含義 |
---|---|
Accept | 瀏覽器能夠處理的內(nèi)容類型 |
Accept-Charset | 瀏覽器能夠顯示的字符集 |
Accept-Encoding | 瀏覽器能處理的壓縮編碼 |
Accept-Language | 瀏覽器當(dāng)前設(shè)置的語(yǔ)言 |
Connection | 瀏覽器與服務(wù)器之間的連接類型 |
Cookie | 當(dāng)前頁(yè)面設(shè)置的任何Cookie |
Host | 發(fā)出請(qǐng)求的頁(yè)面所在的域 |
Referer | 發(fā)出請(qǐng)求的頁(yè)面的URL |
User-Agent | 瀏覽器的用戶代理字符串 |
//使用getResponseHeader()獲取單個(gè)響應(yīng)頭信息
alert(xhr.getResponseHeader('Content-Type'));
//使用getAllResponseHeaders()獲取整個(gè)響應(yīng)頭信息
alert(xhr.getAllResponseHeaders());
//使用setRequestHeader()設(shè)置單個(gè)請(qǐng)求頭信息
xhr.setRequestHeader('MyHeader', 'Lee'); //放在open 方法之后,send 方法之前
我們只可以獲取服務(wù)器返回回來(lái)響應(yīng)頭信息琴许,無(wú)法獲取向服務(wù)器提交的請(qǐng)求頭信息税肪,自然定義的請(qǐng)求頭,在Js端無(wú)法獲取
get請(qǐng)求
get請(qǐng)求常用于向服務(wù)器查詢某些信息虚吟。必要時(shí)寸认,可以將查詢字符串參數(shù)追加到URL的末尾,以便提交給服務(wù)器串慰。
xhr.open('get','demo.php?rand='+Math.random()+'&name=koo',true)
通過URL后的問號(hào)給服務(wù)器傳遞鍵值對(duì)數(shù)據(jù)偏塞,服務(wù)器接收到返回響應(yīng)數(shù)據(jù)。特殊字符
傳參產(chǎn)生的問題可以使用encodeURIComponent()進(jìn)行編碼處理邦鲫,中文字符的返回及傳參灸叼,
可以將頁(yè)面保存和設(shè)置為utf-8 格式即可。
function addURLParam(url, name, value){
url+=(url.indexOf('?')==-1?'?':'&');//判斷的url 是否有已有參數(shù)
url+=encodeURLComponent(name)+'='+encodeURLComponent(value);
return url;
}
post請(qǐng)求
post請(qǐng)求可以包含非常多的數(shù)據(jù)庆捺,我們?cè)谑褂帽韱翁峤坏臅r(shí)候古今,大多使用post傳輸方式。
xhr.open('post','demo.php',true);
而發(fā)送post請(qǐng)求的數(shù)據(jù)滔以,不會(huì)跟在url的尾巴上捉腥,而是通過send()方法向服務(wù)器提交數(shù)據(jù)
xhr.send('name=lee&age=18')
一般來(lái)說(shuō),向服務(wù)器發(fā)送post請(qǐng)求由于解析機(jī)制的原因你画,需要進(jìn)行特別的處理抵碟。因?yàn)閜ost請(qǐng)求和web表單提交不同桃漾,需要使用XHR來(lái)模仿表單提交。
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
從性能上來(lái)講post請(qǐng)求比get請(qǐng)求消耗更多一些拟逮,用相同數(shù)據(jù)比較撬统,get最多比post塊2倍
封裝ajax
function ajax(obj) {
var xhr = new createXHR();
obj.url = obj.url + '?rand=' + Math.random();
obj.data = params(obj.data);
if (obj.method === 'get') obj.url = obj.url.indexOf('?') == -1 ?
obj.url + '?' + obj.data : obj.url + '&' + obj.data;
if (obj.async === true) {
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) callback();
};
}
xhr.open(obj.method, obj.url, obj.async);
if (obj.method === 'post') {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send(obj.data);
} else {
xhr.send(null);
}
if (obj.async === false) {
callback();
}
function callback () {
if (xhr.status == 200) {
obj.success(xhr.responseText); //回調(diào)
} else {
alert('數(shù)據(jù)返回失敗敦迄!狀態(tài)代碼:' + xhr.status + '恋追,
狀態(tài)信息:' + xhr.statusText);
}
}
}
//調(diào)用ajax
addEvent(document, 'click', function () { //IE6 需要重寫addEvent
ajax({
method : 'get',
url : 'demo.php',
data : {
'name' : 'Lee',
'age' : 100
},
success : function (text) {
alert(text);
},
async : true
});
});
//名值對(duì)編碼
function params(data) {
var arr = [];
for (var i in data) {
arr.push(encodeURIComponent(i) + '=' + encodeURIComponent(data[i]));
}
return arr.join('&');
}
新技術(shù)fetch
fetch 是全局量 window 的一個(gè)方法,它的主要特點(diǎn)有:
1罚屋、第一個(gè)參數(shù)是URL:
2苦囱、第二個(gè)是可選參數(shù),可以控制不同配置的 init 對(duì)象
3沿后、使用了 JavaScript Promises 來(lái)處理結(jié)果/回調(diào):
fetch(url, options).then(function(response) {
// handle HTTP response
}, function(error) {
// handle network error
}).catch(fun)//c處理錯(cuò)誤
fetch規(guī)范與jQuery.ajax()主要有兩種方式的不同:
1沿彭、從 fetch()返回的 Promise 將不會(huì)拒絕HTTP錯(cuò)誤狀態(tài), 即使響應(yīng)是一個(gè) HTTP 404 或 500。相反尖滚,它會(huì)正常解決 (其中ok狀態(tài)設(shè)置為false), 并且僅在網(wǎng)絡(luò)故障時(shí)或任何阻止請(qǐng)求完成時(shí),它才會(huì)拒絕瞧柔。
2漆弄、默認(rèn)情況下, fetch在服務(wù)端不會(huì)發(fā)送或接收任何 cookies, 如果站點(diǎn)依賴于維護(hù)一個(gè)用戶會(huì)話,則導(dǎo)致未經(jīng)認(rèn)證的請(qǐng)求(要發(fā)送 cookies造锅,必須發(fā)送憑據(jù)頭).
fetch的使用更簡(jiǎn)單撼唾,通過promise異步機(jī)制來(lái)處理響應(yīng)或錯(cuò)誤,ajax的使用需要一步一步的調(diào)用很多方法
補(bǔ)充:Promise
Promise是異步編程的一種解決方案哥蔚,該對(duì)象有兩個(gè)特點(diǎn):
1倒谷、對(duì)象的狀態(tài)不受外界影響。有三種狀態(tài):Pending
糙箍、Fulfilled
和Rejected
渤愁。只有異步操作的結(jié)果
可以決定
當(dāng)前是哪一種狀態(tài)
,任何其他操作都無(wú)法改變這個(gè)狀態(tài)深夯。
2抖格、一旦狀態(tài)改變就不會(huì)在變。Promise狀態(tài)的改變有兩種:從Pending變?yōu)镕ulfilled和從Pending變?yōu)镽ejected咕晋。只要這兩種情況發(fā)生雹拄,狀態(tài)就不會(huì)再變。這是成為Resolved掌呜。
優(yōu)點(diǎn):1滓玖、可以將異步操作以同步操作的流程表達(dá)出來(lái),避免了層層嵌套的回掉函數(shù)质蕉。
2势篡、接口同意翩肌,控制異步操作更加容易
缺點(diǎn):1、法取消Promise殊霞,一旦創(chuàng)建就會(huì)立即執(zhí)行摧阅。
2、如果不設(shè)置回調(diào)函數(shù)绷蹲,Promise內(nèi)部拋出的錯(cuò)誤不會(huì)反映到外部棒卷。
3、當(dāng)處于Pending狀態(tài)時(shí)祝钢,無(wú)法得知目前進(jìn)展到哪一階段
let promise=new Promise((resolve,reject)=>{
resolve(str)
reject('err')
})
promise.then((str)=>{
console.log(str)//這個(gè)是resolve的回調(diào)
},(reject)=>{
console.log(reject)//這個(gè)是reject的回調(diào)
})
參考資料:JavaScript高級(jí)程序設(shè)計(jì)(第3版)