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

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

簡(jiǎn)介

瀏覽器與服務(wù)器之間,采用HTTP 協(xié)議通信。用戶在瀏覽器地址欄鍵入一個(gè)網(wǎng)址,或者通過網(wǎng)頁表單向服務(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í)并沒有引起注意,直到2004年 Gmail 發(fā)布和2005年 Google Map 發(fā)布,才引起廣泛重視。2005年2月,AJAX 這個(gè)詞第一次正式提出,它是 Asynchronous JavaScript and XML 的縮寫,指的是通過 JavaScript 的異步通信,從服務(wù)器獲取 XML 文檔從中提取數(shù)據(jù),再更新當(dāng)前網(wǎng)頁的對(duì)應(yīng)部分,而不用刷新整個(gè)網(wǎng)頁。后來,AJAX這個(gè)詞就成為JavaScript 腳本發(fā)起 HTTP 通信的代名詞,也就是說,只要用腳本發(fā)起通信,就可以叫做 AJAX 通信。W3C 也在2006年發(fā)布了它的國際標(biāo)準(zhǔn)。

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

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

那么什么是ajax呢
就是一句話,AJAX通過原生的XMLHttpRequest對(duì)象發(fā)出 HTTP 請(qǐng)求,得到服務(wù)器返回的數(shù)據(jù)后,再進(jìn)行處理?,F(xiàn)在,服務(wù)器返回的都是 JSON格式的數(shù)據(jù),XML 格式已經(jīng)過時(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)。

所以我用一句話來總結(jié)兩者的關(guān)系:
我們使用XMLHttpRequest對(duì)象來發(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)聽
    </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à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),握手的過程,每次握手會(huì)發(fā)生改變,可以監(jiān)聽到內(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)聽
        //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,所以可以不寫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ù)寫進(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è)用戶沒有設(shè)置type,則默認(rèn)為GET
            var type = opts.type || 'GET';
            //數(shù)據(jù)類型默認(rèn)為json
            var dataType = opts.dataType || 'json';
            //如果用戶沒有設(shè)置,則傳遞一個(gè)空函數(shù)
            var onsuccess = opts.onsuccess || function(){};
            var onerror = opts.onerror || function(){};
            //如果沒有數(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()方法還沒有調(diào)用。
  • 1:對(duì)應(yīng)常量OPENED,表示send()方法還沒有被調(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ù)器傳來的body部分的數(shù)據(jù),如果responseType屬性是text或者空字符串,responseText就會(huì)包含已經(jīng)收到的部分信息。
  • 4:對(duì)應(yīng)常量DONE,表示服務(wù)器數(shù)據(jù)已經(jīng)完全接收,或者本次接收已經(jīng)失敗了。
    在通信過程中,每當(dāng)發(fā)生狀態(tài)變化的時(shí)候,readyState屬性的值就會(huì)發(fā)生改變。這個(gè)值每一次變化,都會(huì)觸發(fā)readyStatyChange事件。
    responseType
    responseType屬性用來指定服務(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ù)。一般來說,如果通信成功的話,這個(gè)狀態(tài)碼是200。
  • 200:OK,訪問正常
  • 301:Moved Permanently,永久移動(dòng)
  • 302:Move temporarily,暫時(shí)移動(dòng)
  • 304:Not Modified,未修改
  • 307:Temporary Redirect,暫時(shí)重定向
  • 401:Unauthorized,未授權(quán)
  • 403:Forbidden,禁止訪問
  • 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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容