AJAX的應(yīng)用與詳解

我們平常工作中經(jīng)常會(huì)用到ajax向服務(wù)器發(fā)送請(qǐng)求蹂喻,今天就來(lái)詳細(xì)的來(lái)了解一下ajax的前世與今生氨肌!

簡(jiǎn)介

瀏覽器與服務(wù)器之間莺治,采用HTTP 協(xié)議通信廓鞠。用戶在瀏覽器地址欄鍵入一個(gè)網(wǎng)址帚稠,或者通過(guò)網(wǎng)頁(yè)表單向服務(wù)器提交內(nèi)容,這時(shí)瀏覽器就會(huì)向服務(wù)器發(fā)出 HTTP 請(qǐng)求床佳。

1999年滋早,微軟公司發(fā)布 IE 瀏覽器5.0版,第一次引入新功能:允許 JavaScript 腳本向服務(wù)器發(fā)起 HTTP請(qǐng)求砌们。這個(gè)功能當(dāng)時(shí)并沒(méi)有引起注意杆麸,直到2004年 Gmail 發(fā)布和2005年 Google Map 發(fā)布,才引起廣泛重視浪感。2005年2月昔头,AJAX 這個(gè)詞第一次正式提出,它是 Asynchronous JavaScript and XML 的縮寫(xiě)影兽,指的是通過(guò) JavaScript 的異步通信揭斧,從服務(wù)器獲取 XML 文檔從中提取數(shù)據(jù),再更新當(dāng)前網(wǎng)頁(yè)的對(duì)應(yīng)部分峻堰,而不用刷新整個(gè)網(wǎng)頁(yè)讹开。后來(lái),AJAX這個(gè)詞就成為JavaScript 腳本發(fā)起 HTTP 通信的代名詞捐名,也就是說(shuō)旦万,只要用腳本發(fā)起通信,就可以叫做 AJAX 通信桐筏。W3C 也在2006年發(fā)布了它的國(guó)際標(biāo)準(zhǔn)纸型。

AJAX 包括以下幾個(gè)步驟。

  • 創(chuàng)建XMLHttpRequest
  • 發(fā)出 HTTP請(qǐng)求
  • 接受服務(wù)器傳回的數(shù)據(jù)
  • 更新網(wǎng)頁(yè)數(shù)據(jù)

那么什么是ajax呢
就是一句話梅忌,AJAX通過(guò)原生的XMLHttpRequest對(duì)象發(fā)出 HTTP 請(qǐng)求狰腌,得到服務(wù)器返回的數(shù)據(jù)后,再進(jìn)行處理∧恋現(xiàn)在琼腔,服務(wù)器返回的都是 JSON格式的數(shù)據(jù),XML 格式已經(jīng)過(guò)時(shí)了踱葛,但是 AJAX 這個(gè)名字已經(jīng)成了一個(gè)通用名詞丹莲,字面含義已經(jīng)消失了。
ajax是一種技術(shù)方案尸诽,但并不是一種新技術(shù)甥材。它依賴的是現(xiàn)有的CSS/HTML/Javascript,而其中最核心的依賴是瀏覽器提供的XMLHttpRequest對(duì)象性含,是這個(gè)對(duì)象使得瀏覽器可以發(fā)出HTTP請(qǐng)求與接收HTTP響應(yīng)洲赵。

所以我用一句話來(lái)總結(jié)兩者的關(guān)系:
我們使用XMLHttpRequest對(duì)象來(lái)發(fā)送一個(gè)Ajax請(qǐng)求。 具體請(qǐng)參考這里:XMLHttpRequest

創(chuàng)建

實(shí)現(xiàn)一個(gè)最簡(jiǎn)單功能的Ajax

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Ajax</title>
</head>
<body>
    <script>
        var xhr = new XMLHttpRequest() //創(chuàng)建一個(gè)對(duì)象
        xhr.open('GET', '/hello.json', true)//設(shè)置參數(shù),請(qǐng)求的類型叠萍,地址芝发,是否使用異步
        //hello.json 可以把他當(dāng)作一個(gè)資源,而不是一個(gè)文件
        //true為異步苛谷,false為同步獲取的方式
        xhr.send()//發(fā)送請(qǐng)求
        //內(nèi)部數(shù)據(jù)到達(dá)會(huì)默認(rèn)觸發(fā)load
        xhr.addEventListener('load', function(){ 
            var data = xhr.responseText;
            console.log(data);
        })//監(jiān)聽(tīng)
    </script>

對(duì)請(qǐng)求狀態(tài)進(jìn)行判斷 看是否請(qǐng)求成功

<script>
        var xhr = new XMLHttpRequest()
        xhr.open('GET', '/hello2.json', true)//請(qǐng)求不存在的文件冷守,404 not found
        xhr.send()//發(fā)送請(qǐng)求
        
         //監(jiān)聽(tīng)通信狀態(tài)的變化
        xhr.onreadystatechange = function(){
            if(xhr.readyState ===4 && xhr.status ===200){
                console.log(xhr.responseText);
            }
        }

        xhr.addEvenListener('onreadystatechange' = function(){
            console.log('readyState:', xhr.readyState); 
            //準(zhǔn)備狀態(tài)凌唬,握手的過(guò)程羊赵,每次握手會(huì)發(fā)生改變蹬昌,可以監(jiān)聽(tīng)到內(nèi)部狀態(tài)的改變
        })

        xhr.addEventListener('load', function(){ 
        //內(nèi)部數(shù)據(jù)到達(dá)會(huì)默認(rèn)觸發(fā)load
            console.log(xhr.status);
            if((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304){    
            //304 請(qǐng)求緩存
            //成功了
                var data = xhr.responseText;
                console.log(data);
            }else{
                console.log('error');
            }
            xhr.onerror = function(){ //內(nèi)部出現(xiàn)錯(cuò)誤
                console.log('error');//例如斷網(wǎng),數(shù)據(jù)還未到達(dá)服務(wù)器
            }
            xhr.ontimeout = function(){ //超時(shí)

            }
        }) //監(jiān)聽(tīng)
        //status: 服務(wù)器的一個(gè)狀態(tài)赫蛇,數(shù)據(jù)是否OK
        //readystate: 交互流程是否完畢绵患,0-4 五個(gè)狀態(tài)
        //load: 狀態(tài)為4時(shí)會(huì)自動(dòng)觸發(fā)load,交互完畢一定是4悟耘,所以可以不寫(xiě)readystate
    </script>

POST方法

<script>
        var xhr = new XMLHttpRequest();
        xhr.open('POST', '/login', true);
        //把需要發(fā)送的數(shù)據(jù)拼好放在send中
        xhr.send('username=zuodong&password=123');
        //也可以將這個(gè)函數(shù)寫(xiě)進(jìn)send中落蝙,拼接URL
        /*makeUrl({
            username: 'zuodong',
            age: 23
        })*/        


        //需要發(fā)送的數(shù)據(jù),函數(shù)的方式
        /*makeUrl({
            username: 'zuodong',
            age: 23
        })*/

        xhr.addEventListener('load', function(){
            console.log(xhr.status);
            if((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304){ //304 請(qǐng)求緩存
                var data = xhr.responseText;
                console.log(data);
            }else{
                console.log('error');
            }
        })
        xhr.onerror = function(){ //內(nèi)部出現(xiàn)錯(cuò)誤
                console.log('error');//例如斷網(wǎng)暂幼,數(shù)據(jù)還未到達(dá)服務(wù)器
            }
        makeUrl({
            username: 'zuodong',
            age: 23
        })
        function makeUrl(obj){
            var arr = []
            for(var key in obj){
                arr.push( key + '=' + obj[key])
            }
            return arr.join('&')
        }
        //最終拼接成:username=zuodong&password=123
    </script>
</body>
</html>

封裝AJAX

<script>
        function ajax(opts){
            var url = opts.url;
            //假設(shè)用戶沒(méi)有設(shè)置type筏勒,則默認(rèn)為GET
            var type = opts.type || 'GET';
            //數(shù)據(jù)類型默認(rèn)為json
            var dataType = opts.dataType || 'json';
            //如果用戶沒(méi)有設(shè)置,則傳遞一個(gè)空函數(shù)
            var onsuccess = opts.onsuccess || function(){};
            var onerror = opts.onerror || function(){};
            //如果沒(méi)有數(shù)據(jù)旺嬉,默認(rèn)傳遞一個(gè)空數(shù)據(jù)
            var data = opts.data || {};

            //將用戶傳遞的參數(shù)管行,如用戶名密碼,將這個(gè)對(duì)象進(jìn)行一個(gè)處理邪媳,序列化
            var dataStr = [];
            for(var key in data){
                dataStr.push(key + '=' + data[key]);
            }
            dataStr = dataStr.join('&');


            if(type === 'GET'){
                url +='?' + dataStr;
            }

            var xhr = new XMLHttpRequest();
            xhr.open(type, url, true);
            xhr.onload = function(){
                if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
                    //成功了
                    //如果用戶設(shè)置的需要返回的數(shù)據(jù)類型需要的是json格式
                    if(dataType === 'json'){
                        //把對(duì)象返回的數(shù)據(jù)解析成json格式
                        onsuccess(JSON.parse(xhr.responseText));
                    }else{
                        onsuccess(shr.responseText);
                    }
                }else{
                    //如果是其他狀態(tài)捐顷,調(diào)用用戶的onerror
                    onerror();
                }
        }
                xhr.onerror = onerror;
                if(type === 'POST'){
                    xhr.send(dataStr);
                }else{
                    xhr.send();
                }
            }


            //約定好的需要傳遞的參數(shù)
            ajax({
                url: 'http://api.jirengu.com/weather.php',
                data: {
                    city: '北京'
                },
                onsuccess: function(ret){
                    console.log(ret)
                },
                onerror: function(){
                    console.log('服務(wù)器異常');
                }
            })
    </script>

XMLHttpRequest實(shí)例的屬性

readyState
只讀屬性,用一個(gè)正數(shù)對(duì)應(yīng)的常量雨效,表示XMLHttpRequest請(qǐng)求當(dāng)前所處的狀態(tài)迅涮。

  • 0:對(duì)用常量UNSET,表示XMLHttpRequest實(shí)例已經(jīng)生成徽龟,但是open()方法還沒(méi)有調(diào)用叮姑。
  • 1:對(duì)應(yīng)常量OPENED,表示send()方法還沒(méi)有被調(diào)用据悔,任然可以使用setRequestHeader()传透,設(shè)定HTTP請(qǐng)求頭信息。
  • 2:對(duì)應(yīng)常量HEADERS_RECEIVED极颓,表示send()方法已經(jīng)執(zhí)行朱盐,并且頭信息和狀態(tài)碼已收到。
  • 3:對(duì)應(yīng)常量LOADING菠隆,表示正在接受服務(wù)器傳來(lái)的body部分的數(shù)據(jù)兵琳,如果responseType屬性是text或者空字符串骚烧,responseText就會(huì)包含已經(jīng)收到的部分信息。
  • 4:對(duì)應(yīng)常量DONE闰围,表示服務(wù)器數(shù)據(jù)已經(jīng)完全接收,或者本次接收已經(jīng)失敗了既峡。
    在通信過(guò)程中羡榴,每當(dāng)發(fā)生狀態(tài)變化的時(shí)候,readyState屬性的值就會(huì)發(fā)生改變运敢。這個(gè)值每一次變化校仑,都會(huì)觸發(fā)readyStatyChange事件。
    responseType
    responseType屬性用來(lái)指定服務(wù)器返回?cái)?shù)據(jù)類型传惠。
    "":字符串(默認(rèn)值)
    arraybuffer:ArrayBuffer對(duì)象
    blob:Blob對(duì)象
    document:Document對(duì)象
    json:JSON對(duì)象
    text:字符串
    status
    status屬性為只讀屬性迄沫,表示本次請(qǐng)求所得到的HTTP狀態(tài)碼,它是一個(gè)整數(shù)卦方。一般來(lái)說(shuō)羊瘩,如果通信成功的話,這個(gè)狀態(tài)碼是200盼砍。
  • 200:OK尘吗,訪問(wèn)正常
  • 301:Moved Permanently,永久移動(dòng)
  • 302:Move temporarily浇坐,暫時(shí)移動(dòng)
  • 304:Not Modified睬捶,未修改
  • 307:Temporary Redirect,暫時(shí)重定向
  • 401:Unauthorized近刘,未授權(quán)
  • 403:Forbidden擒贸,禁止訪問(wèn)
  • 404:Not Found,未發(fā)現(xiàn)指定網(wǎng)址
  • 500:Internal Server Error觉渴,服務(wù)器發(fā)生錯(cuò)誤
    基本只有2xx和304的狀態(tài)碼介劫,表示服務(wù)器返回是正常狀態(tài)。

詳細(xì)教程
參考這里
阮一峰教程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末疆拘,一起剝皮案震驚了整個(gè)濱河市蜕猫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌哎迄,老刑警劉巖回右,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異漱挚,居然都是意外死亡翔烁,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門旨涝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蹬屹,“玉大人,你說(shuō)我怎么就攤上這事】” “怎么了贩耐?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)厦取。 經(jīng)常有香客問(wèn)我潮太,道長(zhǎng),這世上最難降的妖魔是什么虾攻? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任铡买,我火速辦了婚禮,結(jié)果婚禮上霎箍,老公的妹妹穿的比我還像新娘奇钞。我一直安慰自己,他們只是感情好漂坏,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布景埃。 她就那樣靜靜地躺著,像睡著了一般顶别。 火紅的嫁衣襯著肌膚如雪纠亚。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,554評(píng)論 1 305
  • 那天筋夏,我揣著相機(jī)與錄音蒂胞,去河邊找鬼。 笑死条篷,一個(gè)胖子當(dāng)著我的面吹牛骗随,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播赴叹,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼鸿染,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了乞巧?” 一聲冷哼從身側(cè)響起涨椒,我...
    開(kāi)封第一講書(shū)人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎绽媒,沒(méi)想到半個(gè)月后蚕冬,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡是辕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年囤热,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片获三。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡旁蔼,死狀恐怖锨苏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情棺聊,我是刑警寧澤伞租,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站限佩,受9級(jí)特大地震影響肯夏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜犀暑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望烁兰。 院中可真熱鬧耐亏,春花似錦、人聲如沸沪斟。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)主之。三九已至择吊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間槽奕,已是汗流浹背几睛。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留粤攒,地道東北人所森。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像夯接,于是被迫代替她去往敵國(guó)和親焕济。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

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