二纺涤、ajax

認識AJAX

掃盲1:

AJAX: Asynchronous Javascript And XML
html: 超文本標記語言数焊,W3C指定了很多具有語義化的標記標簽疯搅,用以搭建頁面結構(目前多用V4/V5版本)
xhtml: 更加嚴謹?shù)膆tml
dhtml: 頁面中的數(shù)據是動態(tài)綁定的
xml: 可擴展的標記標簽語言表制,它里面使用的標簽都是自己定義的健爬,用來存儲數(shù)據,結構清晰么介,以前用的比較多浑劳,不過其二次解析的過程相對JSON比較麻煩,目前前端數(shù)據多用JSON

   <root>
       <student>
           <name>唐玄奘</name>
           <age>18</age>
       </student>
   </root>

wxml: 微信小程序的頁面就是.wxml夭拌,小程序中使用的標簽都是小程序自己定義的(微信XML)

掃盲2:

這里的異步不能理解為JS中的同步異步編程魔熏,這里面的異步指的是‘局部刷新’,如果用六個字概述AJAX的作用鸽扁,那就是:實現(xiàn)局部刷新

在web1.0和web 2.0時代=>整體刷新
那時前端頁面的功能和數(shù)據綁定大部分都是后臺開發(fā)者使用后臺語言來完成的蒜绽,瀏覽器只有一個作用,就是把后臺實現(xiàn)好的功能的頁面呈現(xiàn)即可桶现,所有操作的都是后臺服務器完成躲雅,這樣若前端頁面需要改變,必須后臺把最新的內容重新返回骡和,前端頁面需要重新刷新

作用:

  • 如果客戶端獲取的是資源文件相赁,瀏覽器會自動幫我們向服務器端發(fā)送請求,并接收服務器返回的內容進行渲染:
  • 在地址欄輸入網址
  • 利用link
  • 利用script
  • 利用iframe
  • ...
  • 但如果我們需要請求的是數(shù)據慰于,就需要AJAX等技術發(fā)送請求(AJAX是JS中的一個核心知識點)
    AJAX獲取數(shù)據四部曲:

    //創(chuàng)建ajax對象xhr
    var xhr = new XMLHttpRequest();//ie6及以下不兼容,用new ActiveXObject
    var data = null;

    //打開一個url钮科,配置請求的基本參數(shù)信息
    xhr.open('get','temp.xml?name=zf',true);
    //[請求方式]:get post put delete head
    //[請求的url地址]
    //[同步或者異步]:默認是true(異步),false(同步)
    //設置請求的用戶名和密碼:[userName],[userPass]提供安全權限的驗證(一般不用)

    xhr.setRequestHeader('key','value');//

    //監(jiān)聽ajax狀態(tài)改變婆赠,獲取服務器返回數(shù)據
    xhr.onreadystatechange = function () {
        if(xhr.readyState === 4 && xhr.status === 200){
            //xhr.readyState ajax狀態(tài)碼 0 1 2 3 4
            //xhr.status 服務器返回的http網絡狀態(tài)碼200 301 302 304 400 401 404 500 503...
            
            data = JSON.PARSE(xhr.responseText) 服務器端響應主體內容绵脯,獲取到的是字符串
            //xhr.responseXML 服務器端響應主體內容,獲取到的是XML格式數(shù)據
           
            //獲取響應頭的兩種方式
            //xhr.getResponseHeader('key')
            //xhr.getAllResponseHeaders()
        }
    };
    xhr.send(null);
    //發(fā)送請求,括號內的傳遞的內容是請求主體

AJAX知識分解

1休里、創(chuàng)建AJAX對象

var xhr = new XMLHttpRequest();//ie6及以下不兼容,用new ActiveXObject

2蛆挫、打來一個請求的url地址

例:xhr.open('get','temp.xml?name=zf',true);
xhr.open([method],[request url],[true/false],[username],[userpass]);
//[method]:get post put delete head
//[request url]
//[true/false]:默認是true(異步),false(同步)妙黍,項目中為防止出現(xiàn)請求阻塞的問題悴侵,大多采用異步
//[userName],[userPass]:設置請求的用戶名和密碼,提供安全權限的驗證(一般不用)
  • method:請求方式
    get:從服務器上獲取數(shù)據(給的少,拿得多拭嫁,最常用的方式)
    post:向服務器推送數(shù)據(給得多可免,拿得少)
    put:給服務器增加資源文件(上傳圖片等)
    delete:從服務器刪除文件
    head:只獲取服務器響應頭信息

注意:無論那種請求方式筒繁,都可以向服務器發(fā)送和接收數(shù)據,且從本質意義上來講他們沒有任何區(qū)別巴元,只是約定俗成的規(guī)則毡咏,在不同的情況下使用不同的請求方式

get與post的區(qū)別:
核心:get通過問號傳參的方式給服務器傳遞內容,而post通過請求主體給服務器傳遞內容

xhr.open('get','temp.json?name=wang&age=18')//get方式逮刨,問號傳參傳遞
xhr.send('{"name":"wang","age":18}'//post方式呕缭,請求主體傳遞

一般get、delete修己、head等用問號傳參的方式給服務器傳遞內容恢总,post、put等用請求主體的方式給服務器傳遞內容
請求方式get系列與post系列之間存在的問題:

  • 大小問題:get傳給服務器內容有大小限制睬愤,post理論上沒有限制:
    因為不同瀏覽器對url長度存在限制片仿,chrome:8k,firefox:7k尤辱,ie:2k砂豌,超出限制部分會被瀏覽器截取,請求主體大小實際上為了保證傳輸?shù)乃俣裙舛剑瑫拗苽鬟f內容大小阳距。

  • 緩存問題:因為get使用問號傳參的方式,如果重復向同一個地址發(fā)送請求结借,瀏覽器會默認做緩存(這個緩存不可控)筐摘,所以我們一般項目中使用get請求時要把緩存清除:

xhr.open('get','temp.json?_=' + Math.random())
//這里的問號傳參中屬性名使用的是下劃線_,是因為除了傳隨機數(shù)外,我們可能還會傳遞其他的信息船老,這樣的話隨機數(shù)的屬性名可能會與其他信息的屬性名沖突咖熟,所以用_做屬性名防止沖突
  • 安全問題:get請求相對于post來說不安全
    有一種黑客技術叫url劫持,被劫持后柳畔,問號后面的參數(shù)值會被獲取或修改馍管,導致不安全

面試題:在你以前的項目中服務器返回的數(shù)據一般是什么格式的

  1. 返回的是字符串格式的
  • 普通的字符串
  • JSON格式字符串(最常用的)
  • 二進制或者文件流編碼格式的字符串(一般請求的是圖片,服務器返回的都是二進制編碼字符串)
  1. 返回的是XML格式的

3荸镊、監(jiān)聽狀態(tài)改變

  • xhr.readyState:AJAX狀態(tài)碼

    • 0 :UNSENT: 未發(fā)送,剛開始創(chuàng)建完成AJAX對象,默認的狀態(tài)就是0
    • 1 :OPENED: 已打開,執(zhí)行了xhr.open之后狀態(tài)變?yōu)?
    • 2 :HEADERS_RECEIVED: 響應頭信息已接收
    • 3 :LOADING: 服務器正在處理咽斧,響應主體內容正在加載
    • 4 :DONE: 響應主體內容已成功返回
  • xhr.status:服務器返回的HTTP狀態(tài)碼

    • 200 :響應主體成功返回
    • 301 :永久重定向(永久轉移) 域名更換的時候會做301永久重定向堪置,如京東的360buy
    • 302 :臨時重定向(臨時轉移) ->307(臨時重定向) 服務器負載均衡:比如一臺服務器最高并發(fā)數(shù)為1000躬存,當?shù)?001個人訪問時,當前服務器不能進行有效處理了舀锨,此時需要把此客戶端的請求臨時轉移到另外一臺服務器上岭洲,這叫做負載均衡
    • 304 :緩存數(shù)據,在真實項目中坎匿,產品一旦上線盾剩,資源圖片雷激、js、css告私、等內容是不輕易改變的屎暇,此時我們最好做一下304緩存,在第一次訪問服務器時驻粟,把加載的資源文件進行緩存根悼,第二次再加載時直接讀取緩存中的數(shù)據,減少服務器壓力蜀撑。瀏覽器強制無緩存刷新快捷鍵:ctrl+f5
    • 400 :客戶端給服務器端請求參數(shù)錯誤
    • 401 :無權限訪問
    • 404 :訪問地址不存在
    • 500 :未知服務器錯誤
    • 503 :服務器超負荷挤巡,未做負載均衡

面試題:你之前的項目中做過倒計時之類的東西嗎?從服務器讀取時間你是怎么解決時間差的酷麦?
由于服務器返回給客戶端的時間信息在響應頭信息的Date屬性中矿卑,所以當我們只需要獲取服務器的時間信息時,可以用head的傳遞方式沃饶,且在監(jiān)聽xhr狀態(tài)時母廷,在readyState狀態(tài)碼為2的時候,就已經獲取到響應頭信息了糊肤,此時就可以獲取到服務器的Date數(shù)據了徘意,就沒必要在狀態(tài)碼為4的時候去獲取信息了,這樣請求的效率更高,代碼如下:

xhr.onreadystatechange = function () {
    if (xhr.status !== 200) return;//if后沒有大括號則只會對if判斷后的第一條語句生效轩褐;
    if (xhr.readyState === 2) {//->我們只需要響應頭信息返回就可以獲取到服務器的時間,如果等到4的時候,雖然也可以獲取到,但是間隔的時間更長了,導致時間差也會變大(真實時間和服務器獲取的時間差值)
        var time = xhr.getResponseHeader('Date');//->獲取到的時間是格林尼治時間(GMT),我們還需要把這個時間變?yōu)楸本r間(GMT+0800)
        time = new Date(time);//轉換為本地客戶端時區(qū)的時間
        console.log(time);
    }
};

4椎咧、發(fā)送ajax請求給服務器

xhr.send(null);
//get系列請求傳遞一般是null,post系列請求把請求主體放在send參數(shù)里

AJAX一次任務的開始和結束標志:

  • 開始:xhr.send(…)
  • 結束:xhr.readyState===4

AJAX方法封裝(仿JQ,基礎版)

jQuery中的ajax方法

下面是jq中的ajax方法調用把介,jq中的ajax有30多個參數(shù)勤讽,一下列舉了部分常用參數(shù)

$.ajax({
            url: 'temp.json',
            method: 'get',//->type:'get' 和這個屬性是一樣的功能的,定義請求方式
            
            dataType: 'json',//->預設服務器返回的數(shù)據內容的格式json(默認)、text拗踢、xml...
            
            data: null,//->設置請求主體的內容,如果是get請求,jQ會把這些內容放到請求地址的末尾,通過問號傳參的方式傳遞給服務器,post請求才是放在請求主體中
            
            cache: true,//->是否保留get請求的緩存,true是保留get緩存,設置成為false是清除緩存(在URL末尾加隨機數(shù)),此參數(shù)對于post請求無效
            
            async: true,//->設置同步異步,默認是TRUE代表異步
            
            //timeout:3000,//->設置請求超時的時間,如果超過3000ms,當前請求自動中斷(一般不用)
            
            success: function (result) {
                //->當數(shù)據請求成功后執(zhí)行的回調函數(shù),result就是從服務器獲取的結果
                console.log(result);
            },
            
            error: function (msg) {
                //->當數(shù)據請求失敗指定的回調函數(shù),msg就是失敗的原因
            }
        });

以下是仿jQ的ajax基礎版方法源碼(注釋版)

(function () {

    //->驗證當前的URL中是否包含問號,包含返回&,否則返回?
    function check(url) {
        return url.indexOf('?') > -1 ? '&' : '?';
    }

    //->把對象轉換為字符串
    function formatData(obj) {
        var str = '';
        for (var key in obj) {
            if (obj.hasOwnProperty(key)) {
                str += key + '=' + obj[key] + '&';
            }
        }
        str = str.substring(0, str.length - 1);
        return str;
    }

    function ajax(options) {

        //1脚牍、設置參數(shù)的默認值
        var _default = {//設置參數(shù)默認值,default是關鍵字 所以要加下劃線
            url: null,
            method: 'get',
            data: null,
            dataType: 'json',//->text巢墅、xml...
            async: true,
            cache: true,
            success: null,
            error: null
        };

        //2诸狭、使用傳遞進來的參數(shù)配置值把默認值進行替換
        for (var key in options) {
            if (options.hasOwnProperty(key)) {
                //for in循環(huán)可以遍歷到__proto__公有屬性中自己拓展的方法,所以先判斷一下是不是私有屬性
                if (key === 'type') {
                    _default['method'] = options['type'];
                    continue;
                }
                _default[key] = options[key];
            }
        }

        //3君纫、發(fā)送AJAX請求
        var xhr = new XMLHttpRequest;
        var regGET = /^(get|delete|head)$/i;
        
        //->3.3:處理DATA
        //對象和字符串的區(qū)分,如果是對象需要轉換為字符串:xxx=xxx&xxx=xxx...
        if (_default.data !== null) {
            if (typeof _default.data === 'object') {
                _default.data = formatData(_default.data);
            }
            //GET和POST的區(qū)分,GET是把內容放在問號后面
            if (regGET.test(_default.method)) {
                char = check(_default.url);
                _default.url += char + _default.data;
                _default.data = null;//->在發(fā)送的時候GET請求的請求主體是null
            }
        }

        //->3.2:處理CACHE,如果當前的請求是GET系列的,并且CACHE等于FALSE,我們清除緩存
        if (regGET.test(_default.method) && _default.cache === false) {
            var char = check(_default.url);
            _default.url += char + '_=' + Math.random();
        }

        xhr.open(_default.method, _default.url, _default.async);
        xhr.onreadystatechange = function () {
            if (/^(2|3)\d{2}$/.test(xhr.status)) {
                if (xhr.readyState === 4) {
                    
                    //->3.1:我們從服務器端獲取的數(shù)據一般都是字符串格式的,但是我們傳遞進來的參數(shù)值中的dataType預設了最后數(shù)據結果的類型驯遇,所以我們還需要自己進行數(shù)據的二次加工,把從服務器端獲取的字符串轉換為預設的結果
                    var result = xhr.responseText; 
                    switch (_default.dataType.toUpperCase()) {
                        case 'JSON':
                            result = 'JSON' in window ? JSON.parse(result) : eval('(' + result + ')');
                            break;
                        case 'XML':
                            result = xhr.responseXML;
                            break;
                    }
                    _default.success && _default.success.call(xhr, result);
                }
                //->問題:JQ中的dataType是否影響了服務器的返回結果? 不影響,服務器端會根據產品需求給我們返回字符串或者XML數(shù)據,而JQ會根據我們設置的dataType值,把返回的結果二次解析成需要的類型
                return;
            }
            //->失敗:執(zhí)行ERROR的回調函數(shù),讓函數(shù)中的THIS指向當前實例XHR,并且把錯誤信息傳遞給回調函數(shù)
            //typeof _default.error === 'function' ? _default.error.call(xhr, xhr.responseText) : null;
            _default.error && _default.error.call(xhr, xhr.responseText);//->這種寫法和上面的相同,都是在判斷只有傳遞了回調函數(shù)的情況下才會執(zhí)行(項目中一般都這么寫)
        };
        xhr.send(_default.data);
    }

    window.ajax = ajax;
}())();

以下是仿jQ的ajax基礎版方法源碼(無注釋版)

~function () {
    function check(url) {
        return url.indexOf('?') > -1 ? '&' : '?';
    }

    function formatData(obj) {
        var str = '';
        for (var key in obj) {
            if (obj.hasOwnProperty(key)) {
                str += key + '=' + obj[key] + '&';
            }
        }
        str = str.substring(0, str.length - 1);
        return str;
    }

    function ajax(options) {
        var _default = {
            url: null,
            method: 'get',
            data: null,
            dataType: 'json',
            async: true,
            cache: true,
            success: null,
            error: null
        };
        for (var key in options) {
            if (options.hasOwnProperty(key)) {
                if (key === 'type') {
                    _default['method'] = options['type'];
                    continue;
                }
                _default[key] = options[key];
            }
        }
        var xhr = new XMLHttpRequest;
        var regGET = /^(get|delete|head)$/i;
        if (_default.data !== null) {
            if (typeof _default.data === 'object') {
                _default.data = formatData(_default.data);
            }
            if (regGET.test(_default.method)) {
                char = check(_default.url);
                _default.url += char + _default.data;
                _default.data = null;
            }
        }
        if (regGET.test(_default.method) && _default.cache === false) {
            var char = check(_default.url);
            _default.url += char + '_=' + Math.random();
        }
        xhr.open(_default.method, _default.url, _default.async);
        xhr.onreadystatechange = function () {
            if (/^(2|3)\d{2}$/.test(xhr.status)) {
                if (xhr.readyState === 4) {
                    var result = xhr.responseText;
                    switch (_default.dataType.toUpperCase()) {
                        case 'JSON':
                            result = 'JSON' in window ? JSON.parse(result) : eval('(' + result + ')');
                            break;
                        case 'XML':
                            result = xhr.responseXML;
                            break;
                    }
                    _default.success && _default.success.call(xhr, result);
                }
                return;
            }
            _default.error && _default.error.call(xhr, xhr.responseText);
        };
        xhr.send(_default.data);
    }

    window.ajax = ajax;
}();
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末蓄髓,一起剝皮案震驚了整個濱河市叉庐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌会喝,老刑警劉巖陡叠,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件玩郊,死亡現(xiàn)場離奇詭異,居然都是意外死亡枉阵,警方通過查閱死者的電腦和手機译红,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來兴溜,“玉大人临庇,你說我怎么就攤上這事£腔牛” “怎么了假夺?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長斋攀。 經常有香客問我已卷,道長,這世上最難降的妖魔是什么淳蔼? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任侧蘸,我火速辦了婚禮,結果婚禮上鹉梨,老公的妹妹穿的比我還像新娘讳癌。我一直安慰自己,他們只是感情好存皂,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布晌坤。 她就那樣靜靜地躺著,像睡著了一般旦袋。 火紅的嫁衣襯著肌膚如雪骤菠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天疤孕,我揣著相機與錄音商乎,去河邊找鬼。 笑死祭阀,一個胖子當著我的面吹牛鹉戚,可吹牛的內容都是我干的。 我是一名探鬼主播专控,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼抹凳,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了踩官?” 一聲冷哼從身側響起却桶,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蔗牡,沒想到半個月后颖系,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡辩越,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年嘁扼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片黔攒。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡趁啸,死狀恐怖,靈堂內的尸體忽然破棺而出督惰,到底是詐尸還是另有隱情不傅,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布赏胚,位于F島的核電站访娶,受9級特大地震影響,放射性物質發(fā)生泄漏觉阅。R本人自食惡果不足惜崖疤,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望典勇。 院中可真熱鬧劫哼,春花似錦、人聲如沸割笙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽伤溉。三九已至豪嚎,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谈火,已是汗流浹背侈询。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留糯耍,地道東北人扔字。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像温技,于是被迫代替她去往敵國和親革为。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內容

  • AJAX 原生js操作ajax 1.創(chuàng)建XMLHttpRequest對象 var xhr = new XMLHtt...
    碧玉含香閱讀 3,201評論 0 7
  • 大家好抛虏,我是IT修真院深圳分院第3期的學員博其,一枚正直純潔善良的前端程序員,今天給大家分享一下迂猴,修真院官網前端工程師...
    大大頭大閱讀 7,674評論 1 72
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理慕淡,服務發(fā)現(xiàn),斷路器沸毁,智...
    卡卡羅2017閱讀 134,659評論 18 139
  • 本文詳細介紹了 XMLHttpRequest 相關知識峰髓,涉及內容: AJAX、XMLHTTP息尺、XMLHttpReq...
    semlinker閱讀 13,662評論 2 18
  • Ajax的基本概念及使用 同步&異步 同步:必須等待前面的任務完成携兵,才能繼續(xù)后面的任務; 異步:不受當前主要任務的...
    magic_pill閱讀 1,955評論 0 5