AJAX
要想要知道AJAX是什么呢,首先要知道一般情況下客戶端都會(huì)從服務(wù)器獲取了一些什么類型的文件;
- 如果客戶端在服務(wù)器需要獲取的是資源文件,瀏覽器會(huì)自動(dòng)幫我們向服務(wù)器發(fā)送請(qǐng)求,并且接收服務(wù)器返回的內(nèi)容進(jìn)行渲染,最終顯示出來;(這里的資源文件包括JS,HTML,CSS,IMG等類型)
向服務(wù)器發(fā)送請(qǐng)求資源文件基本可通過:
- 在地址欄輸入網(wǎng)址
- 利用LINK
- 利用SCRIPT
- 利用IFRAME
- ...
- 但是如果我們需要向服務(wù)器請(qǐng)求的是數(shù)據(jù)(這里的數(shù)據(jù)可能是json、text、xml等格式的),就需要使用AJAX等技術(shù)發(fā)送請(qǐng)求了(AJAX是JS中的一個(gè)核心重要知識(shí)點(diǎn))
‘AJAX 不是新的編程語言,而是一種使用現(xiàn)有標(biāo)準(zhǔn)的新方法。’ ---W3C的官方解釋
所以什么是AJAX:
AJAX: Async(Asynchronous) JavaScript And Xml
翻譯過來就是 :異步的JavaScript和Xml
來自W3C的解釋:
AJAX 是一種用于創(chuàng)建快速動(dòng)態(tài)網(wǎng)頁的技術(shù)。通過在后臺(tái)與服務(wù)器進(jìn)行少量數(shù)據(jù)交換,AJAX 可以使網(wǎng)頁實(shí)現(xiàn)異步更新。這意味著可以在不重新加載整個(gè)網(wǎng)頁的情況下,對(duì)網(wǎng)頁的某部分進(jìn)行更新。
- 那么什么又是XML
- AJAX叫做異步更新,難道使用異步請(qǐng)求嗎?
掃盲1 : 什么是XML
- html :超文本標(biāo)記語言,W3C制定了很多具有語義化的標(biāo)記標(biāo)簽,我們使用這些HTML標(biāo)簽搭建頁面結(jié)構(gòu)(目前用的比較多的是 v4/v5(HTML5)版本)
- xhtml:更加嚴(yán)格的HTML (用的比較少了)
- dhtml:頁面中的數(shù)據(jù)是動(dòng)態(tài)綁定的 (非官方標(biāo)準(zhǔn)語言)
- xml :可擴(kuò)展的標(biāo)記標(biāo)簽語言,它里面使用的標(biāo)簽都是自己定義的,也不是W3C的規(guī)范標(biāo)簽
- 我們可以使用自己定義的有意義的標(biāo)簽來存儲(chǔ)數(shù)據(jù),這樣結(jié)構(gòu)清晰明了(目前前端數(shù)據(jù)存儲(chǔ)和展示一般都使用JSON,但是之前一般都是XML)
以前項(xiàng)目中服務(wù)器返回給客戶端的數(shù)據(jù)類型一般都是XML格式的,只不過XML格式的數(shù)據(jù)在客戶端的二次解析過程中相對(duì)于JSON比較麻煩,現(xiàn)在服務(wù)器端返回給客戶端的數(shù)據(jù)一般都是JSON格式的數(shù)據(jù);但是也有XML格式的數(shù)據(jù);
- wxml:微信小程序的頁面就是.wxml ,小程序中使用的標(biāo)簽都是小程序自己定義的(微信XHML)
掃盲2 :異步JS -> 異步更新
在web1.0 web2.0時(shí)代初期, ==> 整體刷新
前端頁面中的功能和數(shù)據(jù)綁定大部分都是后臺(tái)開發(fā)者使用后臺(tái)語言來完成的;瀏覽器只有一個(gè)作用,就是把后臺(tái)實(shí)現(xiàn)好的功能的頁面呈現(xiàn)即可,所有的操作都是后臺(tái)在服務(wù)器完成的;這樣的話如果前端頁面中的內(nèi)容需要改變的話,必須后臺(tái)重新把最新的內(nèi)容返回,前端需要重新呈現(xiàn),導(dǎo)致整個(gè)前端頁面都刷新;
AJAX 里的Async(異步)先不要理解為JS中的同步異步編程(這樣會(huì)很混亂),這里面的異步可以先理解為‘局部刷新’,如果用七個(gè)字概述AJAX的作用,那就記住 “實(shí)現(xiàn)局部刷新的” 就Ok了;
舉一個(gè)非常簡(jiǎn)單的運(yùn)用AJAX的例子:
注冊(cè)百度賬號(hào)頁面中,
【運(yùn)用AJAX】注冊(cè)過程中,如果填寫一個(gè)已經(jīng)被注冊(cè)的手機(jī)號(hào),此時(shí),在點(diǎn)擊驗(yàn)證碼選框時(shí),該手機(jī)號(hào)的數(shù)據(jù)內(nèi)容便會(huì)傳送到服務(wù)器端進(jìn)行驗(yàn)證,會(huì)立馬彈出此手機(jī)已經(jīng)被綁定過的提示框;
【沒有運(yùn)用AJAX】整個(gè)數(shù)據(jù)傳輸過程中不會(huì)有任何提示框出現(xiàn),只有在全部表單填寫完成點(diǎn)擊注冊(cè)后完成一次數(shù)據(jù)傳輸,與服務(wù)器建立連接進(jìn)行確認(rèn),如果此時(shí)該手機(jī)被注冊(cè)的話,整個(gè)注冊(cè)頁面會(huì)被重新刷新后才會(huì)返回該手機(jī)被綁定的數(shù)據(jù)信息,并且之前表單中填寫信息都在刷新后清空,體驗(yàn)極差,所以一般此類頁面為了增加用戶體驗(yàn)都會(huì)運(yùn)用到AJAX;當(dāng)然還有很多運(yùn)用場(chǎng)景...
簡(jiǎn)單實(shí)現(xiàn)AJAX的基本步驟
1、 創(chuàng)建AJAX對(duì)象
var xhr = new XMLHttpRequest(); // ->IE6 下不兼容 不兼容用 new ActiveXObject
2 、打開一個(gè)請(qǐng)求的URL地址
xhr.open([method],[request url],[async/sync]);
- [method] : 請(qǐng)求方式分為兩大系列:
- get系列:
- get : 獲取 (應(yīng)用于從服務(wù)器端獲取內(nèi)容)
- delete :刪除,應(yīng)用于刪除服務(wù)器上的內(nèi)容
- head :應(yīng)用于只想獲取服務(wù)器響應(yīng)頭信息
- post系列:
- post : 推送,應(yīng)用于給服務(wù)器推送內(nèi)容
- put : 放,應(yīng)用于在服務(wù)器上放文件等
- ...
- 還有更多的請(qǐng)求方式
ps: 以上的幾種方式,客戶端都可以把內(nèi)容傳遞給服務(wù)器,服務(wù)器也可以把內(nèi)容返回給客戶端,只不過在不同的場(chǎng)景,我們使用對(duì)應(yīng)的類型會(huì)更好一些,以上沒有硬性規(guī)定,方式可以互換。只不過大家形成了一種約定俗成的默契,例如:
給服務(wù)器少,從服務(wù)器拿的多,我們最好用GET請(qǐng)求
給服務(wù)器多,從服務(wù)器拿的少,我們最好用POST請(qǐng)求
get請(qǐng)求和post請(qǐng)求的區(qū)別:
核心:
- get請(qǐng)求傳遞給服務(wù)器的內(nèi)容是通過問號(hào)傳參的方式傳遞的;
xhr.open('get','temp.json?xxx=xxx&xxx=xx') - post傳遞給服務(wù)器的內(nèi)容是用過請(qǐng)求主體傳遞的 ;
xhr.send(...)
(1) GET傳遞給服務(wù)器的內(nèi)容沒有POST請(qǐng)求多 :
每一個(gè)瀏覽器對(duì)url的長度都有限制(谷歌8kb、火狐7kb、ie2kb),如果get請(qǐng)求下傳遞的比較多,url就會(huì)超出限制,超出的限制部分瀏覽器自動(dòng)截取,導(dǎo)致服務(wù)器獲取的內(nèi)容不完整;
而請(qǐng)求主體中的大小理論上是沒有限制的,但真實(shí)項(xiàng)目中為了保證傳輸?shù)乃俣龋覀儠?huì)限制傳遞內(nèi)容的大小.
(2) GET請(qǐng)求容易出現(xiàn)緩存 :
還是因?yàn)槭褂脝柼?hào)傳參的方式,如果重復(fù)向同一個(gè)地址發(fā)送請(qǐng)求,傳遞的參數(shù)值都是一樣的,瀏覽器會(huì)默認(rèn)的給做緩存(這個(gè)緩存不可控),所以我們一般項(xiàng)目中在使用get請(qǐng)求的時(shí)候都要把緩存清除掉;
xhr.open('get','temp.json?_='+Math.random());
(3) GET請(qǐng)求相對(duì)于POST來說不安全 :
有一種黑客技術(shù)叫做‘url劫持’,被劫持后,問號(hào)后面的參數(shù)值都會(huì)被獲取或者修改,導(dǎo)致不安全
- [request url] :請(qǐng)求數(shù)據(jù)的接口地址,客戶端也是通過這個(gè)地址向服務(wù)器發(fā)送請(qǐng)求的,客戶端可以通過問號(hào)傳參的方式吧內(nèi)容傳遞給服務(wù)器;
xhr.open('get','temp.json?name = zhangsan&age=18',true);
-
[async/sync] : 同步或者異步,默認(rèn)true 代表異步,可不寫;
在真實(shí)項(xiàng)目中,為了防止出現(xiàn)請(qǐng)求堵塞的問題,我們大部分采用的是異步
比如請(qǐng)求文件比較大,如果時(shí)間很長,響應(yīng)時(shí)間比較長就會(huì)影響后面的數(shù)據(jù)
3 、監(jiān)聽AJAX狀態(tài)改變,在不同的狀態(tài)下處理不同的事情
xhr.onreadystatechange = function(){
if(xhr.readyState===4 && xhr.status ===200){
var val = xhr.responseText;
// -> xhr.getResponseHeader([key]) 獲取響應(yīng)頭信息
// -> xhr.responseText: 獲取的是字符串(一般是服務(wù)器響應(yīng)主體
//返回的JSON字符串)
// -> xhr.responseXML: 獲取的是XML數(shù)據(jù)
}
}
xhr.readyState :AJAX狀態(tài)碼
0 UNSENT : 未發(fā)送,剛開始創(chuàng)建完成AJAX對(duì)象,默認(rèn)的狀態(tài)就是0
1 OPENED : 已打開,執(zhí)行了xhr.open之后狀態(tài)變?yōu)?
2 HEADERS_RECEIVED :響應(yīng)頭信息已經(jīng)成功的返回并且被接收
3 LOADING : 響應(yīng)主體內(nèi)容正在加載
4 DONE :響應(yīng)主體內(nèi)容接收成功
- xhr.status : 服務(wù)器返回的HTTP網(wǎng)絡(luò)狀態(tài)碼
200 : 請(qǐng)求成功
【 3 開頭的都是成功但是有轉(zhuǎn)折】
301 : 永久重定向(永久轉(zhuǎn)移) 例如:訪問京東以前的域名www.360buy.com;
在控制臺(tái)network里,可以看到301,域名更換的時(shí)候我們基本上都會(huì)做301做永久的重定向;
302 : 臨時(shí)重定向(臨時(shí)轉(zhuǎn)移) --> 307(臨時(shí)重定向) ;例如:一臺(tái)服務(wù)器最高并發(fā)數(shù)在500左右,當(dāng)501個(gè)人過來的時(shí)候,當(dāng)前服務(wù)器不能有效的進(jìn)行處理了,此時(shí)我們需要把此客戶端的請(qǐng)求臨時(shí)轉(zhuǎn)移到另外一臺(tái)服務(wù)器上進(jìn)行處理;
304 : 讀取的是緩存的數(shù)據(jù),在真實(shí)的項(xiàng)目中,產(chǎn)品一旦上線,資源圖片、JS、CSS等內(nèi)容是不輕易改變的,此時(shí)我們最好做一下304緩存:第一次向服務(wù)器發(fā)送請(qǐng)求來訪問的時(shí)候,把加載完成的資源文件進(jìn)行緩存,第二次直接讀取緩存中的數(shù)據(jù)即可,減少服務(wù)器壓力;
【4開頭的一般都是客戶端的錯(cuò)誤】
400 請(qǐng)求參數(shù)有誤
401 請(qǐng)求的權(quán)限不夠
404 請(qǐng)求的地址不存在
【服務(wù)器端的錯(cuò)誤】
500 未知的服務(wù)器端錯(cuò)誤 (停電,著火,服務(wù)器爆炸等等不可預(yù)知錯(cuò)誤....)
503 服務(wù)器超負(fù)荷 (春運(yùn)搶票的時(shí)候你一定會(huì)看到這個(gè)狀態(tài))
4 、發(fā)送AJAX請(qǐng)求給服務(wù)器
xhr.send(null);
// -GET系列請(qǐng)求傳遞的一般都是null,因?yàn)樗麄兺ㄟ^問號(hào)傳參把內(nèi)容傳遞給服務(wù)器
// -POST系列的請(qǐng)求會(huì)把需要傳遞給服務(wù)器的內(nèi)容放在這里(請(qǐng)求主體);
AJAX整個(gè)過程中開始和結(jié)束標(biāo)志事件:
開始的標(biāo)志:xhr.send(...)
結(jié)束的標(biāo)志:xhr.readyState === 4
利用JQuery 實(shí)現(xiàn)AJAX
<script src="jquery.min.js"></script>
$.ajax({
url: 'temp.json',
method: 'get',
//->type:'get' 和這個(gè)屬性是一樣的功能的,除了寫get還可以寫post、head、delete、put...
dataType: 'json',
//->預(yù)設(shè)服務(wù)器返回的數(shù)據(jù)內(nèi)容的格式j(luò)son(默認(rèn))、text、xml...
data: null,
//->設(shè)置請(qǐng)求主體的內(nèi)容,如果是GET請(qǐng)求,JQ會(huì)把這些內(nèi)容放到請(qǐng)求地址的末尾,通過問號(hào)傳參的方式傳遞給服務(wù)器,POST請(qǐng)求才是放在請(qǐng)求主體中
cache: true,
//->是否保留GET請(qǐng)求的緩存,TRUE是保留也就是不清除GET緩存,設(shè)置成為FALSE是清除緩存(在URL末尾加隨機(jī)數(shù)),此參數(shù)對(duì)于POST請(qǐng)求無效
async: true,
//->設(shè)置同步異步,默認(rèn)是TRUE代表異步
//timeout:3000,//->設(shè)置請(qǐng)求超時(shí)的時(shí)間,如果超過3000MS,當(dāng)前請(qǐng)求自動(dòng)中斷(一般不用)
success: function (result) {
//->當(dāng)數(shù)據(jù)請(qǐng)求成功后執(zhí)行的回調(diào)函數(shù),result就是從服務(wù)器獲取的結(jié)果
console.log(result);
},
error: function (msg) {
//->當(dāng)數(shù)據(jù)請(qǐng)求失敗指定的回調(diào)函數(shù),msg就是失敗的原因
}
});
// JQ中的參數(shù)配置大概在20多個(gè)左右,以上只是最常用的幾個(gè)
/*
* [data]
* get->放在URL末尾
* post->放在請(qǐng)求主體
*
* 字符串->寫的是什么傳遞就是什么
* 對(duì)象->會(huì)把對(duì)象變成 key1=value1&key2=value2... 傳遞給服務(wù)器
*/
最后分享一道面試題:
問:有做過類似于倒計(jì)時(shí)的項(xiàng)目嗎,做的時(shí)候當(dāng)前時(shí)間是從客戶端本地讀取的還是從服務(wù)器讀取的?從服務(wù)讀取時(shí)間你是怎么解決時(shí)間差的?
<script>
/*
* 獲取服務(wù)器的時(shí)間,我們不需要再響應(yīng)主體中獲取,在響應(yīng)頭的信息中,
* 有一個(gè)叫做Date的屬性,它存儲(chǔ)的值就是服務(wù)器的時(shí)間
*/
var xhr = new XMLHttpRequest();
xhr.open('head', 'temp.xml?_=' + Math.random());
//->為什么選擇HEAD請(qǐng)求方式?因?yàn)楫?dāng)前的需求,我們只想獲取到服務(wù)器時(shí)間,
//這樣的話只需要把響應(yīng)頭信息獲取到即可,主體內(nèi)容不需要獲取了,
//使用HEAD就是只獲取頭信息,加大請(qǐng)求的效率;
xhr.onreadystatechange = function () {
if (xhr.status !== 200) return;
if (xhr.readyState === 2) {
//->我們只需要響應(yīng)頭信息返回就可以獲取到服務(wù)器的時(shí)間,如果等到4的時(shí)候,
//雖然也可以獲取到,但是間隔的時(shí)間更長了,導(dǎo)致時(shí)間差也會(huì)變大(真實(shí)時(shí)間和服務(wù)器獲取的時(shí)間差值)
var time = xhr.getResponseHeader('Date');
//->獲取到的時(shí)間是格林尼治時(shí)間(GMT),我們還需要把這個(gè)時(shí)間變?yōu)楸本r(shí)間(GMT+0800)
time = new Date(time);
console.log(time);
}
};
xhr.send(null);
</script>
以上就是對(duì)AJAX的一個(gè)初步的探索啦,這技術(shù)出道這么久,一直只聞其名不見其聲的技術(shù),還真有點(diǎn)相見恨晚的趕腳啊....
相信初學(xué)者看完此篇應(yīng)該會(huì)對(duì)AJAX有一個(gè)初步的理解了,目前也探索到這里,一起繼續(xù)探索吧,騷年們,如有異議,歡迎指正~!