JavaScript性能提升之——提升響應(yīng)速度

首先呢样傍,這里說的響應(yīng)速度调煎,是指頁面UI的響應(yīng)速度镜遣,對一個(gè)用戶界面來說,評判快的標(biāo)準(zhǔn)是什么士袄?

用戶覺得快才是快悲关。

優(yōu)化UI線程

說到底產(chǎn)品最終都是給用戶使用的谎僻,不論你對自己的產(chǎn)品做了什么優(yōu)化,在用戶手里好用就是好用寓辱,快就是快艘绍,不是靠你開發(fā)者說這說那用了什么技術(shù)啊來判定的。那么在網(wǎng)頁中讶舰,怎么才會(huì)顯得快呢鞍盗?

提高用戶界面的響應(yīng)速度一般有兩種方式:

  • 提升代碼質(zhì)量來提升響應(yīng)速度;
  • 讓用戶覺得你快跳昼。

說到提升響應(yīng)速度般甲,我們得先來說一下瀏覽器的UI線程。

瀏覽器UI線程

這個(gè)東西呢就是用來執(zhí)行JavaScript和更新用戶界面的進(jìn)程啦鹅颊。

UI線程是基于一個(gè)簡單的隊(duì)列系統(tǒng)的敷存,所有的任務(wù)(UI更新、執(zhí)行JavaScript)都會(huì)被放到任務(wù)隊(duì)列中堪伍,任務(wù)會(huì)被保存到隊(duì)列中直到進(jìn)程空閑锚烦,一旦空閑,隊(duì)列中的下一個(gè)任務(wù)就會(huì)被重新提取出來運(yùn)行帝雇。也就是說對瀏覽器來說涮俄,頁面上出現(xiàn)的所有事情,執(zhí)行js尸闸、重繪頁面這些都要一件件來做彻亲。

引用一下 《You Don't Know JavaScript:Types & Grammar,Async &Performance》書中的一段偽代碼來解釋下這個(gè)概念:

//eventLoop是一個(gè)用作隊(duì)列的數(shù)組
var eventLoop = [];
var event;

//'永遠(yuǎn)'執(zhí)行
while(true){
  if(eventLoop.length>0){
    event = eventLoop.shift();
    try{
      event();
    }
    catch(err){
      reportError(err);
    }
  }
}

結(jié)合這段概念代碼,實(shí)際上我們的頁面產(chǎn)生的所有操作吮廉,讀取苞尝、解析資源、渲染頁面宦芦、重繪宙址,執(zhí)行js等等這些任務(wù)全部都會(huì)在隊(duì)列里排隊(duì)執(zhí)行。
當(dāng)UI線程處于執(zhí)行任務(wù)期間调卑,如果用戶在這個(gè)時(shí)候與之交互抡砂,會(huì)出現(xiàn)UI沒有即時(shí)更新,更有可能出現(xiàn)UI的更新任務(wù)不會(huì)被創(chuàng)建令野,在我們平時(shí)看來就是點(diǎn)擊了沒反應(yīng)舀患,連按鈕都沒一點(diǎn)反饋?zhàn)兓@種時(shí)候就是UI線程處于繁忙狀態(tài)气破。

出現(xiàn)這種情況的時(shí)候很可能是因?yàn)槟愕膉s運(yùn)行時(shí)間過長了,現(xiàn)在的瀏覽器有些會(huì)有限制運(yùn)行時(shí)間餐抢,超過時(shí)間會(huì)彈出提示框现使。這種情況我覺得還是遇到的次數(shù)挺多的= =低匙;

相當(dāng)多的歷史研究中有提到過,單個(gè)js的操作花費(fèi)時(shí)間不應(yīng)該超過100ms碳锈。

我們自己使用網(wǎng)頁的時(shí)候也會(huì)有感覺顽冶,我點(diǎn)了這個(gè)按鈕過了一會(huì)才有反應(yīng),完全就給了人一種這網(wǎng)站很慢的感覺售碳。

使用定時(shí)器讓出UI線程

雖然說單個(gè)js任務(wù)應(yīng)該在100毫秒內(nèi)完成强重,但是有時(shí)候有些任務(wù)確實(shí)要花費(fèi)較長時(shí)間,這個(gè)時(shí)候可以使用定時(shí)器來讓出UI線程使用權(quán)贸人,我們在看別人代碼的時(shí)候應(yīng)該也有見過設(shè)置一個(gè)setTimeout任務(wù)但是延遲又設(shè)置的很低的用法间景,這就是使用定時(shí)器來讓出UI線程。

首先要明確的一點(diǎn)是艺智,定時(shí)器并不會(huì)一執(zhí)行把你要延遲的任務(wù)加入到事件循環(huán)隊(duì)列中倘要,它只是設(shè)置定時(shí)器到時(shí)后,再把你要延遲的這個(gè)任務(wù)加入到隊(duì)列中十拣,這也是定時(shí)器精度可能不高的原因封拧,因?yàn)槿绻愕綍r(shí)間的時(shí)候剛好前面還有很多任務(wù)沒有被執(zhí)行完,那你這個(gè)只能等啦夭问。

用定時(shí)器取代循環(huán)

說那么多泽西,什么情況下可以用定時(shí)器來做代碼塊拆分運(yùn)行優(yōu)化呢,很常見的js運(yùn)行時(shí)間過長的例子是循環(huán)缰趋,有些循環(huán)處理函數(shù)過于復(fù)雜或者循環(huán)源的大小過大捧杉,我們就可以使用,但是這也是有前提的埠胖,使用定時(shí)器取代循環(huán)要滿足兩個(gè)條件:處理過程無需同步糠溜,數(shù)據(jù)無需按順序處理。
滿足這兩個(gè)條件之后直撤,我們可以寫一個(gè)簡單的函數(shù)來處理:

function processArray(items,process,callback){
  var todos = item.concat();
  setTimeout(function(){
    process(tudos.shift());
    if(tudos.length>0){
      setTimeout(arguments.callee,25);
    }else{
      callback(items);
    }
  })
}

只要調(diào)用這個(gè)函數(shù)并傳入數(shù)組非竿,處理方法與完成的循環(huán)完成的回調(diào)函數(shù),這樣做會(huì)使原本的循環(huán)時(shí)間變成谋竖,但是每次循環(huán)后都會(huì)讓出UI線程(上面定時(shí)器讓出UI線程有說明)红柱,不至于說讓整個(gè)長時(shí)間的循環(huán)一直占著UI線程而鎖定瀏覽器,雖然實(shí)際上的處理時(shí)間變長了蓖乘,但是對用戶來說卻會(huì)覺得更快了锤悄。

這種定時(shí)器的用法還可以用于分割任務(wù),一個(gè)運(yùn)行時(shí)間過長的函數(shù)可以試著能不能拆分成多個(gè)函數(shù)嘉抒,然后用類似上面的方式來加快UI響應(yīng)速度零聚。

要注意的是,同時(shí)創(chuàng)建多個(gè)重復(fù)的定時(shí)器會(huì)產(chǎn)生所有定時(shí)器一起搶占UI線程而產(chǎn)生性能問題,最好使用一個(gè)定時(shí)器每次執(zhí)行多次操作而不要同時(shí)創(chuàng)建多個(gè)

使用Web Worker

這個(gè)功能屬于提供js能以類似多線程的方式來運(yùn)行的功能隶症,不過實(shí)際上并不是政模。

首先要知道的是,HTML5的Web Worker這個(gè)特性屬于宿主功能蚂会,即瀏覽器提供的功能淋样,本身和JavaScript語言沒關(guān)系,JS本身并沒有任何支持多線程執(zhí)行的功能胁住。

瀏覽器環(huán)境可以提供多個(gè)JavaScript引擎實(shí)例并各自運(yùn)行獨(dú)立的線程上趁猴。利用web worker,我們就可以將程序劃分多塊來并發(fā)運(yùn)行彪见。

Web Worker通常被用于以下幾個(gè)方面:

  • 處理密集型數(shù)學(xué)計(jì)算
  • 大數(shù)據(jù)集排序
  • 數(shù)據(jù)處理(壓縮儡司、音頻分析、圖像處理等)
  • 高流量網(wǎng)絡(luò)通信
    from《You Don't Know JavaScript:Types & Grammar,Async &Performance》

實(shí)例化一個(gè)Worker很簡單: var worker1 = new Worker('http://aa.com/b.js')// 這個(gè)url要指向js文件位置;

當(dāng)這個(gè)文件被加載到一個(gè)Worker之后企巢,瀏覽器就會(huì)啟動(dòng)一個(gè)獨(dú)立的線程來運(yùn)行這個(gè)Worker枫慷。

web worker中使用大多數(shù)的標(biāo)準(zhǔn)javascript特性,包括

  • Navigator
  • XMLHttpRequest
  • Array, Date, Math, and String
  • WindowTimers.setTimeout and WindowTimers.setInterval

完整的Web Worker用法可以參考https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Functions_and_classes_available_to_workers

注意浪规,Worker之間以及他們和主程序之間不會(huì)共享任何作用域或者資源或听,他們之間的聯(lián)系依靠的是一個(gè)基本的事件消息機(jī)制來互相聯(lián)系

Web Worker之間的數(shù)據(jù)傳遞

Worker與網(wǎng)頁通過事件接口來通信

  • 網(wǎng)頁代碼使用postMessage()給Worker傳遞數(shù)據(jù)
  • Worker可以通過注冊 message事件來接收網(wǎng)頁傳遞過來的數(shù)據(jù) worker.onmessage = function(event){},傳遞進(jìn)來的數(shù)據(jù)可以通過event.data訪問到。
    這是唯一的網(wǎng)頁與Worker通信途徑笋婿。

Web Worker的使用場景與瀏覽器的支持比較有限誉裆,就現(xiàn)在來說,常用的場景還是在處理比較大的數(shù)據(jù)缸濒,或者處理與UI無關(guān)的長時(shí)間運(yùn)行腳本足丢,比如轉(zhuǎn)換大量的字符串啦,大數(shù)據(jù)集的搜索排序之類啦庇配。

頁面元素的響應(yīng)處理

這個(gè)的話其實(shí)主要是從用戶體驗(yàn)的角度來“欺騙性的”提高用戶對網(wǎng)站速度的印象斩跌,怎么說呢

當(dāng)用戶與程序交互的時(shí)候,程序要立即給出響應(yīng)

核心就是上面這句話捞慌,立即給出響應(yīng)不表示你的程序要立即處理完任務(wù)耀鸦,而是要立即做出一個(gè)反饋,這個(gè)反饋一般會(huì)是改變觸發(fā)交互元素的外觀啸澡,最常見的就是給可交互按鈕添加各種狀態(tài)袖订,未被觸發(fā)、觸發(fā)中嗅虏、觸發(fā)后最好都要有個(gè)外觀變化洛姑,這對用戶來說是最直觀的,無論觸發(fā)交互的時(shí)候任務(wù)是否完成皮服,都要立即給予對應(yīng)的狀態(tài)來給用戶知道我的操作成功了楞艾,正在處理参咙,處理好了,不給予反饋的交互過程很容易會(huì)讓用戶認(rèn)為出了什么問題产徊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末昂勒,一起剝皮案震驚了整個(gè)濱河市蜀细,隨后出現(xiàn)的幾起案子舟铜,更是在濱河造成了極大的恐慌,老刑警劉巖奠衔,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谆刨,死亡現(xiàn)場離奇詭異,居然都是意外死亡归斤,警方通過查閱死者的電腦和手機(jī)痊夭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來脏里,“玉大人她我,你說我怎么就攤上這事∑群幔” “怎么了番舆?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長矾踱。 經(jīng)常有香客問我恨狈,道長,這世上最難降的妖魔是什么呛讲? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任禾怠,我火速辦了婚禮,結(jié)果婚禮上贝搁,老公的妹妹穿的比我還像新娘吗氏。我一直安慰自己,他們只是感情好雷逆,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布弦讽。 她就那樣靜靜地躺著,像睡著了一般关面。 火紅的嫁衣襯著肌膚如雪坦袍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天等太,我揣著相機(jī)與錄音捂齐,去河邊找鬼。 笑死缩抡,一個(gè)胖子當(dāng)著我的面吹牛奠宜,可吹牛的內(nèi)容都是我干的包颁。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼压真,長吁一口氣:“原來是場噩夢啊……” “哼娩嚼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起滴肿,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤岳悟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后泼差,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贵少,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年堆缘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了滔灶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,505評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吼肥,死狀恐怖录平,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情缀皱,我是刑警寧澤斗这,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站唆鸡,受9級(jí)特大地震影響涝影,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜争占,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一燃逻、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧臂痕,春花似錦伯襟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至澡绩,卻和暖如春稽揭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肥卡。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工溪掀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人步鉴。 一個(gè)月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓揪胃,卻偏偏與公主長得像璃哟,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子喊递,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評論 2 359

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