原生Ajax總結(jié)

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糙箍、FulfilledRejected渤愁。只有異步操作的結(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版)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末比规,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子拦英,更是在濱河造成了極大的恐慌蜒什,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疤估,死亡現(xiàn)場(chǎng)離奇詭異灾常,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)铃拇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門钞瀑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人慷荔,你說(shuō)我怎么就攤上這事雕什。” “怎么了显晶?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵贷岸,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我磷雇,道長(zhǎng)偿警,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任倦春,我火速辦了婚禮户敬,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘睁本。我一直安慰自己尿庐,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布呢堰。 她就那樣靜靜地躺著抄瑟,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上皮假,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天鞋拟,我揣著相機(jī)與錄音,去河邊找鬼惹资。 笑死贺纲,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的褪测。 我是一名探鬼主播猴誊,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼侮措!你這毒婦竟也來(lái)了懈叹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤分扎,失蹤者是張志新(化名)和其女友劉穎澄成,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體畏吓,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡墨状,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了菲饼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片歉胶。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖巴粪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情粥谬,我是刑警寧澤肛根,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站漏策,受9級(jí)特大地震影響派哲,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜掺喻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一芭届、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧感耙,春花似錦褂乍、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至只酥,卻和暖如春褥实,著一層夾襖步出監(jiān)牢的瞬間呀狼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工损离, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留哥艇,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓僻澎,卻偏偏與公主長(zhǎng)得像貌踏,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子怎棱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容