前端效能優化(三)——傳統 JavaScript 優化的誤區

OneAPM官方技術部落格發表於2015-12-22

注:本文是純技術探討文,無圖無笑點,希望您喜歡

一.前言

軟體行業極其缺乏前端人才這是圈內的共識了,某種程度上講,同等水平前端的工資都要比後端高上不少,而圈內的另一項共識則是——網頁是公司的臉面!

幾年前,谷歌的一項統計表明,如果亞馬遜頁面載入每慢 100ms,將影響他們 1% 的收入;如果谷歌頁面載入慢 500ms,流量將銳減 20%,這個資料現在必將更加恐怖!

前端高效能優化(一)(二)中,筆者介紹了一些關於前端優化的技術,這些技術都依賴於前人的辛苦努力,但我們仍要明白的是,前端的情況十分複雜,優化前端效能是必須因地制宜、因時制宜。

在本篇文章中,主要介紹的就是在一些條件下,傳統優化 JavaScript 的技術並不像我們認為的那樣適用。

二.JavaScript 模組化誤區

加快 JavaScript 載入和執行的速度,一直是前端優化的一個熱點。因此我們先來說下 JavaScript 模組化技術的相關知識,希望通過實踐來體現模組化技術在使用時的注意事項,避免濫用。

為什麼會有模組化技術?

長久以來,編寫 JavaScript 一直以檔案為單位,一般一個型別的 JavaScript 功能程式碼會被放在同一個檔案裡。在一個頁面裡,引用的檔案一般是寫死的,也就是不管頁面用不用,只要你引入了這個檔案,這個檔案就會被載入。

舉個例子,我們開發了一個內容複雜、功能強大的頁面,JavaScript 檔案大到 500K,當頁面費勁的把這 500K 載入下來,然而使用者真正只使用了這 500K 裡極少的一部分功能,但我們又不得不把這 500K 載入下來,因為不同的使用者使用的功能點可能不一樣,我們必須滿足所有需求。

而模組化技術提出 按需載入,也就是當使用者觸發該功能的時候,那個功能才真正的被載入。好比 500K 被拆成了 50 個模組,每個模組 10K,當使用者觸發一個功能時,載入 10K,再觸發再載入,以這樣懶載入的方式來載入模組,可以很大的提高響應速度。這樣,管理模組懶載入的技術也隨之誕生。

模組化技術並非到處靠譜!!

之前筆者在網上搜尋到了一個模組化技術:SeaJS。它是一個遵循 CommonJS 規範的 JavaScript 模組載入框架,可以實現 JavaScript 的模組化開發及載入機制。與 JQuery 等 JavaScript 框架不同,SeaJS 不會擴充套件封裝語言特性,而只是實現 JavaScript 的模組化及按模組載入。

SeaJS 的主要目的是令 JavaScript 開發模組化並可以輕鬆愉悅進行載入,將前端工程師從繁重的 JavaScript 檔案及物件依賴處理中解放出來,可以專注於程式碼本身的邏輯。說白了就是有 Lazy Load 的特性,用到某模組時,SeaJS 才會去載入模組的 JS 檔案。我們可以按功能劃分多個模組,觸發模組功能時,SeaJS 先載入功能模組的檔案,然後執行相應的功能。

這個 SeaJS 擁有的特性,初看非常吸引人,它可以說是新定義了一種開發和管理 JavaScript 檔案的模式。遵循這個模式,你會享受起 JavaScript 的開發。

實踐證明,它也的確可以使 JavaScript 模組化,根據功能劃分模組,每個模組對應一個 JavaScript 檔案,當執行到模組的功能,或者你需要載入模組時,模組才會被下載,同時不會造成重複下載。這一切看起來如此的合理,如此的順暢。。。。。

但是在使用後發現了一些 問題:由於當時開發的網站功能相對簡單,JavaScript 檔案並不是非常大,過多的模組,反而會導致總載入的時間變多了。

由於是 Lazy Load 特性,不適合的模組劃分導致網站出現反應慢的現象,原因是得先載入模組的檔案,才能執行模組的功能。當網路情況不好時,該現象表現的更為嚴重!!!

可以說,問題出在了對新技術的不瞭解上,從而出現了問題,預期是 SeaJS 可以處理 JavaScript 優化的問題,因為它具有避免載入不必要模組的功能,結果反而南轅北轍。

總結

雖然嘗試出現了問題,但是,收穫也是巨大的,簡單來說就是以下兩點:

1)因地制宜,根據實際需要使用模組化技術,切勿跟風技術,在自己沒有完全掌握時,謹慎用於產品中。

2)模組如果是懶載入的,粒度不能太小,也就是模組不能太小。

根據 大功能來劃分模組 也是一個不錯的嘗試。

筆者嘗試將所有模組劃分為 基礎模組功能模組 ,基礎模組包括頁面頭部,尾部相關的公共部分,功能模組則根據前後臺劃分,前臺部分,又根據具體的頁面來劃分,能合併到一起的,就合併成一個模組,增加粒度。結果 JavaScript 檔案減少,也達到了預期的效果。

從實際體驗來看,對於流量不大的網站來說,沒有必要使用懶載入 JavaScript 的相關技術,因為本身 JavaScript 檔案就不是非常大。因此在網頁載入時,就可以先載入所需要的模組。避免不必要的延遲。

三.JavaScript 的位置問題

這一部分,我們來說說 JavaScript 的位置問題對網頁網站效能的影響。

為什麼要考慮位置問題?

其實不管是 CSS 還是 JavaScript,都需要考慮位置的問題,因為 HTML 的渲染和載入順序是從上往下,也就是如果前面插入了 JavaScript 的引用,那麼必須等到這個 JavaScript 下載完畢才會渲染後續的部分。

因此 JavaScript 的插入位置就成為一個值得考慮的問題,因為不適合的位置可能引起渲染的延遲等,造成不好的使用者體驗。

傳統方案帶來的問題和思考

CSS 放在頭部,JavaScript 放在尾部,這是傳統的經驗,它的好處是可以讓頁面優先渲染, 從而頁面可以快速顯示。

但有事實往往沒有我們預想的那麼美好。

有的時候會出現這麼一種情況:當頁面已經渲染完畢時,我們立刻去使用網站的功能,但很多時候 功能按鈕會沒有反應。原因也很簡單,就是 JavaScript 放在頁面的尾部,還沒來得及載入。。。。

這就糾結了。。。。

兩種 JavaScript 放置方式,一種放在頭部,一種放在尾部(暫時忽略部分放在頭部,部分放在尾部的方式),一個犧牲了渲染速度,一個犧牲了使用者體驗。所以很多時候 js 的問題我們需要做權衡。

對一般的小型網站來說,使用者體驗問題要遠遠大於頁面渲染的問題,就比如上文提到的那種功能按鈕不可用的情況。而且,如果 JavaScript 不是很大的話,放在頭部就很好,既不會有太久的頁面空白,也能讓其優先載入,二者得到了很好的平衡。

因此,很多經驗上的東西並不是絕對的,一定要根據實際的情況,包括功能特點、伺服器網路情況等來綜合考慮。

為此,筆者寫下一個自認為較為合理的位置選擇方案,僅供參考。

圖 1. 判斷 JavaScript 放置位置決策表

從上面的分類介紹,我們也可以看出,將功能程式碼按型別歸類到不同的 JavaScript 檔案是多麼的重要,比如應該放頭部和應該放尾部的程式碼,最好不要合併在一起,不要等到出問題要優化的時候再去整理和重構,這樣會增加很多不必要的工作量。

這不僅僅是為自己工作負責,也是為後面要讀你程式碼的新人負責。養成好的設計編碼習慣,也是技術積累的一部分。最後再根據 JavaScript 檔案的功能型別,來決定是放在頁面的頭部還是尾部。

四.怎樣確定是不是 JavaScript 的問題?

這個問題在之前的前端高效能優化(一)(二)中也都簡單的說過,之所以在這再次提及是因為確實覺得這個工具用著很舒服。

沒錯,就是舒服。

隨著資訊爆炸時代的到來,網站本身效能也深刻影響著公司的形象、利益等問題。但是大多數前端測試工具都太碎片化,沒有辦法針對多個使用場景,而且很多都是像 yslow 這樣簡單打個分,也不是真實的使用者體驗。前一段時間在網上找到了一款前端效能優化分析工具——Browser Insight,裡面的功能相當全面,而且可以針對多個使用場景,包括:PC端,移動微信,移動瀏覽器,移動webview,還是 真實的使用者體驗,也就是說,使用者訪問你的網頁是什麼樣的,從這個工具中體現出的就是什麼樣子的。

基於 JavaScript 這個維度 Bi 做的也是相當豐富了。

首先是 指令碼錯誤 板塊。Bi 裡面可以從不同的時間維度檢視被監控頁面出現過的指令碼錯誤,具體資訊包括:發生時間、裝置型別、報錯的瀏覽器及其版本號、錯誤堆疊資訊都可以看到,不論是 線上還是線下測試或者頁面維護 都是夠用了。

不但能看到時間、系統、瀏覽器等,還可以具體定位到出錯的程式碼行,這個確實很方便。

圖 2.Bi 指令碼錯誤

其次是頁面響應時間板塊,這個算是意外的收穫了。通過響應時間板塊裡面的慢載入追蹤,可以看到本次慢載入的頁面資源載入情況,然後我們就知道該優化哪個頁面的哪些 js 、css、img等。

圖 3.Bi 資源列表-時序圖

五.前端優化?使用者體驗?

各位看客,如果你真能堅持看到這裡,是否會覺得這篇更像解決使用者體驗問題的文章?但是講心裡話,前端優化的最終目的,難道不是為了改善使用者體驗嗎?

任何基於使用者體驗的方案,都可以叫前端優化技術。

不管使用多麼好的機器、多麼高的技術,響應速度問題總是避免不了的,因此糾結於什麼技術來解決是不實際的。但是有一款好的工具,使用一些小技巧,也可以改善使用者等待的體驗。

比如,我們為每個非 _target 的超連結或者表單的點選,新增點選事件處理,處理邏輯也很簡單,就是設定 3 秒超時,顯示等待對話方塊。如果在 3 秒內頁面發生跳轉,那麼這個等待對話方塊就不會出現,否則會彈出提示使用者等待,從而及時的將響應反饋給使用者,減少使用者空白等待時間。

這並不是什麼高深的技術,但是運用這個技巧,卻可以大大的改善使用者體驗。

各位,我們優化的目的,就是不要讓使用者一直得不到響應,避免空白等待,讓使用者體驗越來越好。

相關文章