《高性能JavaScript》第七章 Ajax

《高性能JavaScript》第七章 Ajax

7.1 數(shù)據(jù)傳輸

Ajax從最基本層面來說,是一種與服務(wù)器通信而無須重載頁面的方法矮烹;數(shù)據(jù)可以從服務(wù)器獲取或者發(fā)送給服務(wù)器。有多種不同的方法建立這種通信通道嘴办,每種方法都有各自的優(yōu)點和限制茸塞。

7.1.1 請求數(shù)據(jù)

五種常用技術(shù)向服務(wù)器請求數(shù)據(jù):

  1. XMLHttpRequest (XHR)
  2. Dynamic script tag insertion
  3. iframes
  4. Comet
  5. Multipart XHR

現(xiàn)代高性能JavaScript使用的是:XHR動態(tài)腳本注入Multipart XHR描沟,其他兩種往往在極端情況下使用飒泻,不做討論。

XMLHttpRequest

XHR是目前最常用的技術(shù)吏廉,它允許異步發(fā)送和接收數(shù)據(jù)泞遗。

var url = '/data.php';
var params = [
 'id=934875',
 'limit=20'
];
var req = new XMLHttpRequest();
req.onreadystatechange = function() { 
    if (req.readyState === 4) {
    var responseHeaders = req.getAllResponseHeaders(); // 獲取響應(yīng)頭信息
    var data = req.responseText; // 獲取數(shù)據(jù)
    // 數(shù)據(jù)處理。席覆。刹孔。
    }
}

req.open('GET', url + '?' + params.join('&'), true);
req.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); // 設(shè)置請求頭信息
req.send(null); // 發(fā)送請求

注意:由于XHR提供了高級的控制,所以瀏覽器對其增加了一些限制娜睛。你不能使用XHR從外域請求數(shù)據(jù),而且低版本IE不僅不支持“流”卦睹,也不會提供readyState為3的狀態(tài)畦戒。

動態(tài)腳本注入

這種技術(shù)克服了XHR的最大限制:跨域請求數(shù)據(jù)。

var scriptElement = document.createElement('script');
scriptElement.src = 'http://any-domain.com/javascript/lib.js';
document.getElementsByTagName_r('head')[0].appendChild(scriptElement);

但是與XHR相比结序,動態(tài)腳本注入提供的控制是有限的障斋。不能設(shè)置請求頭,只能用GET,不能設(shè)置超時處理等垃环。最后一點特別重要邀层,不能使用純XML、純JSON或其他格式數(shù)據(jù)遂庄,無論哪種格式寥院,都必須封裝在一個回調(diào)函數(shù)里。

var scriptElement = document.createElement('script');
scriptElement.src = 'http://any-domain.com/javascript/lib.js';
document.getElementsByTagName_r('head')[0].appendChild(scriptElement); 
function jsonCallback(jsonString) {
    var data = ('(' + jsonString + ')');
    // 數(shù)據(jù)處理涛目。秸谢。。
}

注意:使用這種技術(shù)從那些你無法直接控制的服務(wù)器上請求數(shù)據(jù)時需要小心霹肝。JavaScript沒有任何權(quán)限和訪問控制的概念估蹄,因此你使用動態(tài)腳本注入添加到頁面的任何代碼都可以完全控制整個頁面。引入外部來源的代碼時務(wù)必多加小心沫换。

Multipart XHR

MXHR是一項最新的技術(shù)臭蚁,它允許客戶端只用一個HTTP請求就可以從服務(wù)器向客戶端傳送多個資源。它通過在服務(wù)器將資源打包成雙方約定的字符串分割的長字符串并發(fā)送給客戶端讯赏。
這個技術(shù)有一些缺點垮兑,其中最大的缺點是這種方式獲取的資源不能被瀏覽器緩存。但某些情況下待逞,MXHR依然能顯著提高整體性能:

  1. 頁面包含了大量其他地方用不到的資源甥角,即不需要緩存,尤其是圖片识樱;
  2. 網(wǎng)站已經(jīng)在每個頁面中使用一個獨立打包的JavaScript或CSS文件以減少HTTP請求嗤无;因為對每個頁面來說這些文件都是唯一的,所以不需要緩存中讀取數(shù)據(jù)怜庸,觸發(fā)重載頁面当犯;

7.1.2 發(fā)送數(shù)據(jù)

有時并不關(guān)心接收數(shù)據(jù),只需要向服務(wù)器發(fā)送數(shù)據(jù)割疾。當數(shù)據(jù)只需要發(fā)送到服務(wù)器時嚎卫,有兩種技術(shù)使用廣發(fā):XHR信標(beacons)

XMLHttpRequest

雖然XHR主要用于從服務(wù)器獲取數(shù)據(jù)宏榕,但也可以將數(shù)據(jù)傳回服務(wù)器拓诸。

GET:適用于傳輸少量數(shù)據(jù)。因為對于少量數(shù)據(jù)而言麻昼,GET請求只需要往服務(wù)器發(fā)送一個數(shù)據(jù)包奠支;而POST至少要發(fā)送兩個數(shù)據(jù)包(頭信息和正文)。
POST:POST適合發(fā)送大數(shù)據(jù)到服務(wù)器抚芦。因為它不關(guān)心額外數(shù)據(jù)包的數(shù)量倍谜;另一個原因是IE對URL長度有限制(2048個字符)迈螟,URL太長了就不能使用GET請求。

Beacons

這個技術(shù)非常類似動態(tài)腳本注入尔崔。它使用JavaScript創(chuàng)建一個新的Image對象答毫,并把src屬性設(shè)外服務(wù)器上腳本的URL。該URL包含了我們要通過GET請求傳回的鍵值對數(shù)據(jù)季春。

var url = '/status_tracker.php';
var params = [
 'step=2',
 'time=1248027314'
];
(new Image()).src = url + '?' + params.join('&');

服務(wù)器接收到數(shù)據(jù)并保存下來洗搂,無須向客戶端返回任何信息,因此沒有圖片會顯示出來鹤盒。

7.2 數(shù)據(jù)格式

當考慮數(shù)據(jù)傳輸技術(shù)時蚕脏,我們必須考慮:功能集、兼容性侦锯、性能及方向驼鞭。而當考慮數(shù)據(jù)格式時,唯一需要比較的標準就是:速度尺碰。

7.2.1 XML

當Ajax最開始流行時挣棕,它選擇XML作為數(shù)據(jù)格式。當時它有很多優(yōu)勢:極佳的通用性亲桥、格式嚴格洛心、易于操作。那時JSON還沒有正式作為交換格式题篷,幾乎所有的服務(wù)端語音都有操作XML的類庫词身。

<?xml version="1.0" encoding='UTF-8'?>
<users total="4">
    <user id="1"> 
        <username>alice</username>
        <realname>Alice Smith</realname>
        <email>alice@alicesmith.com</email>
    </user>
    <user id="2">
        <username>bob</username>
        <realname>Bob Jones</realname>
        <email>bob@bobjones.com</email>
    </user>
    <user id="3">
        <username>carol</username>
        <realname>Carol Williams</realname>
        <email>carol@carolwilliams.com</email>
    </user>
    <user id="4">
        <username>dave</username>
        <realname>Dave Johnson</realname>
        <email>dave@davejohnson.com</email>
    </user>
</users>

可以對其進行優(yōu)化:

<?xml version="1.0" encoding='UTF-8'?>
<users total="4">
    <user id="1-id001" username="alice" realname="Alice Smith" email="alice@alicesmith.com" />
    <user id="2-id001" username="bob" realname="Bob Jones" email="bob@bobjones.com" />
    <user id="3-id001" username="carol" realname="Carol Williams" email="carol@carolwilliams.com" />
    <user id="4-id001" username="dave" realname="Dave Johnson" email="dave@davejohnson.com" />
</users>

性能優(yōu)化:簡化版的XML更有效率,但是比那些最快的格式依然慢上一個數(shù)量級番枚。在高性能Ajax中法严,XML沒有立足之地。

7.2.2 JSON

JSON是一種JavaScript對象和數(shù)組直接量編寫的輕量級且易于解析的數(shù)據(jù)格式葫笼。

[
    {"id":1, "username":"alice", "realname": "Alice Smith", "email":"alice@alicesmith.com"},
    {"id":2, "username":"bob", "realname": "Bob Jones", "email":"bob@bobjones.com"},
    {"id":3, "username":"carol", "realname": "Carol Williams","email":"carol@carolwilliams.com"},
    {"id":4, "username":"dave", "realname": "Dave Johnson", "email":"dave@davejohnson.com"}
]

可以進行簡化:

[
    { "i": 1, "u": "alice", "r": "Alice Smith", "e": "alice@alicesmith.com" },
    { "i": 2, "u": "bob", "r": "Bob Jones", "e": "bob@bobjones.com" },
    { "i": 3, "u": "carol", "r": "Carol Williams", "e": "carol@carolwilliams.com" },
    { "i": 4, "u": "dave", "r": "Dave Johnson", "e": "dave@davejohnson.com" }
]

進一步簡化:

[
    [ 1, "alice", "Alice Smith", "alice@alicesmith.com" ],
    [ 2, "bob", "Bob Jones", "bob@bobjones.com" ],
    [ 3, "carol", "Carol Williams", "carol@carolwilliams.com" ],
    [ 4, "dave", "Dave Johnson", "dave@davejohnson.com" ]
]

在不斷的簡化過程中深啤,可讀性越來越差,也更脆弱路星。但是文件尺寸卻小得多:大約只有標準JSON的一半溯街。解析也必須按照數(shù)據(jù)的順序進行。

function parseJSON(responseText) {
    var users = [];
    var usersArray = ('(' + responseText + ')');
    for (var i = 0, len = usersArray.length; i < len; i++) {
        users[i] = {
            id: usersArray[i][0],
            username: usersArray[i][1],
            realname: usersArray[i][2],
            email: usersArray[i][3]
        };
    }
    return users;
}

7.2.3 HTML

一種可考慮的技術(shù)是在服務(wù)器端構(gòu)建好整個HTML再傳回客戶端洋丐,JavaScript可以通過innerHTML屬性把它插入頁碼相應(yīng)位置呈昔。但問題是HTML是一種臃腫的數(shù)據(jù)格式,比XML更復雜友绝。因此堤尾,作為一種數(shù)據(jù)格式,它既緩慢九榔,又臃腫。

7.2.4 自定義格式

理想的數(shù)據(jù)格式應(yīng)該只包含必要的結(jié)構(gòu),以便你可以分解出每個獨立的字段哲泊。

1:alice:Alice Smith:alice@alicesmith.com;
2:bob:Bob Jones:bob@bobjones.com; 
3:carol:Carol Williams:carol@carolwilliams.com;
4:dave:Dave Johnson:dave@davejohnson.com

這種格式非常簡潔剩蟀,“數(shù)據(jù)/結(jié)構(gòu)”比例相當高,比其他任何格式都高(除了純文本)切威。只需要簡單地調(diào)用字符串split()方法并傳入分隔符作為參數(shù)即可育特,復雜一點的加上循環(huán)就好了。JavaScript中的循環(huán)和split()方法都是相當快的先朦。

7.2.5 數(shù)據(jù)格式總結(jié)

通常來說缰冤,數(shù)據(jù)格式越輕量級越好,JSON字符分隔的自定義是最好的喳魏。

7.3 Ajax性能指南

7.3.1 緩存數(shù)據(jù)

最快的Ajax請求就是沒有請求棉浸。可以有兩種方法來實現(xiàn):

  1. 在服務(wù)端,設(shè)置HTTP頭信息以確保響應(yīng)會被瀏覽器緩存刺彩;
  2. 在客戶端迷郑,把獲取到的信息存儲在本地,以避免再次請求创倔。

7.3.2 了解Ajax類庫的局限

所有得JavaScript庫都允許你訪問一個Ajax對象嗡害,它屏蔽瀏覽器之間的差異,給你一個統(tǒng)一的接口畦攘。大多數(shù)情況下這非常好霸妹,因為它使你可以關(guān)注你的項目,而不是那些古怪的瀏覽器上XHR的工作細節(jié)知押。然而叹螟,為了給你一個統(tǒng)一的接口,這些庫必須簡化接口朗徊,因為不是所有瀏覽器都實現(xiàn)了每個功能首妖。這使得你不能訪問XMLHttpRequest的完整功能。

性能優(yōu)化:直接操作XHR對象減少了函數(shù)的開銷爷恳,進一步提升了性能有缆。但是,如果放棄Ajax類庫温亲,那么你可能在一些古怪的瀏覽器上遇到一些問題棚壁。

歡迎大佬糾錯指導,歡迎同行交流學習栈虚。

GitHub:https://github.com/Code4GL
簡書:http://www.reibang.com/u/7f5541a6b6d2
知乎:https://www.zhihu.com/people/code4gl/activities
公眾號:code_everything
QQ:771841496
郵箱:guanli1991@163.com

掃碼關(guān)注公眾號code_everything
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末袖外,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子魂务,更是在濱河造成了極大的恐慌曼验,老刑警劉巖泌射,帶你破解...
    沈念sama閱讀 211,348評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鬓照,居然都是意外死亡熔酷,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評論 2 385
  • 文/潘曉璐 我一進店門豺裆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拒秘,“玉大人,你說我怎么就攤上這事臭猜√删疲” “怎么了?”我有些...
    開封第一講書人閱讀 156,936評論 0 347
  • 文/不壞的土叔 我叫張陵蔑歌,是天一觀的道長羹应。 經(jīng)常有香客問我,道長丐膝,這世上最難降的妖魔是什么量愧? 我笑而不...
    開封第一講書人閱讀 56,427評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮帅矗,結(jié)果婚禮上偎肃,老公的妹妹穿的比我還像新娘。我一直安慰自己浑此,他們只是感情好累颂,可當我...
    茶點故事閱讀 65,467評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著凛俱,像睡著了一般紊馏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蒲犬,一...
    開封第一講書人閱讀 49,785評論 1 290
  • 那天朱监,我揣著相機與錄音刘莹,去河邊找鬼百姓。 笑死,一個胖子當著我的面吹牛络拌,可吹牛的內(nèi)容都是我干的奋隶。 我是一名探鬼主播擂送,決...
    沈念sama閱讀 38,931評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼唯欣!你這毒婦竟也來了嘹吨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,696評論 0 266
  • 序言:老撾萬榮一對情侶失蹤境氢,失蹤者是張志新(化名)和其女友劉穎蟀拷,沒想到半個月后碰纬,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,141評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡问芬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,483評論 2 327
  • 正文 我和宋清朗相戀三年嘀趟,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片愈诚。...
    茶點故事閱讀 38,625評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖牛隅,靈堂內(nèi)的尸體忽然破棺而出炕柔,到底是詐尸還是另有隱情,我是刑警寧澤媒佣,帶...
    沈念sama閱讀 34,291評論 4 329
  • 正文 年R本政府宣布匕累,位于F島的核電站,受9級特大地震影響默伍,放射性物質(zhì)發(fā)生泄漏欢嘿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,892評論 3 312
  • 文/蒙蒙 一也糊、第九天 我趴在偏房一處隱蔽的房頂上張望炼蹦。 院中可真熱鬧,春花似錦狸剃、人聲如沸掐隐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽虑省。三九已至,卻和暖如春探颈,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背训措。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工伪节, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人隙弛。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓架馋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親全闷。 傳聞我的和親對象是個殘疾皇子叉寂,可洞房花燭夜當晚...
    茶點故事閱讀 43,492評論 2 348

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