一.前言
軟件行業(yè)極其缺乏前端人才這是圈內的共識了,某種程度上講痪枫,同等水平前端的工資都要比后端高上不少奶陈,而圈內的另一項共識則是——網頁是公司的臉面!
幾年前吃粒,谷歌的一項統(tǒng)計表明徐勃,如果亞馬遜頁面加載每慢 100ms,將影響他們 1% 的收入肖爵;如果谷歌頁面加載慢 500ms檐涝,流量將銳減 20%,這個數據現(xiàn)在必將更加恐怖!
在前端高性能優(yōu)化(一)凡纳、(二)中荐糜,筆者介紹了一些關于前端優(yōu)化的技術葛超,這些技術都依賴于前人的辛苦努力延塑,但我們仍要明白的是,前端的情況十分復雜侥涵,優(yōu)化前端性能是必須因地制宜宋雏、因時制宜磨总。
在本篇文章中,主要介紹的就是在一些條件下蚪燕,傳統(tǒng)優(yōu)化 JavaScript 的技術并不像我們認為的那樣適用馆纳。
二.JavaScript 模塊化誤區(qū)
加快 JavaScript 加載和執(zhí)行的速度,一直是前端優(yōu)化的一個熱點累榜。因此我們先來說下 JavaScript 模塊化技術的相關知識灵嫌,希望通過實踐來體現(xiàn)模塊化技術在使用時的注意事項,避免濫用猖凛。
為什么會有模塊化技術绪穆?
長久以來,編寫 JavaScript 一直以文件為單位菠红,一般一個類型的 JavaScript 功能代碼會被放在同一個文件里难菌。在一個頁面里郊酒,引用的文件一般是寫死的键袱,也就是不管頁面用不用摹闽,只要你引入了這個文件,這個文件就會被加載澜汤。
舉個例子倘屹,我們開發(fā)了一個內容復雜纽匙、功能強大的頁面,JavaScript 文件大到 500K馏段,當頁面費勁的把這 500K 加載下來践瓷,然而用戶真正只使用了這 500K 里極少的一部分功能,但我們又不得不把這 500K 加載下來喷舀,因為不同的用戶使用的功能點可能不一樣淋肾,我們必須滿足所有需求。
而模塊化技術提出按需加載拿愧,也就是當用戶觸發(fā)該功能的時候碌尔,那個功能才真正的被加載唾戚。好比 500K 被拆成了 50 個模塊,每個模塊 10K膳灶,當用戶觸發(fā)一個功能時立由,加載 10K,再觸發(fā)再加載毕箍,以這樣懶加載的方式來加載模塊道盏,可以很大的提高響應速度荷逞。這樣,管理模塊懶加載的技術也隨之誕生涩澡。
模塊化技術并非到處靠譜!!
之前筆者在網上搜索到了一個模塊化技術:SeaJS坠敷。它是一個遵循 CommonJS 規(guī)范的 JavaScript 模塊加載框架,可以實現(xiàn) JavaScript 的模塊化開發(fā)及加載機制粥帚。與 JQuery 等 JavaScript 框架不同限次,SeaJS 不會擴展封裝語言特性卖漫,而只是實現(xiàn) JavaScript 的模塊化及按模塊加載。
SeaJS 的主要目的是令 JavaScript 開發(fā)模塊化并可以輕松愉悅進行加載依啰,將前端工程師從繁重的 JavaScript 文件及對象依賴處理中解放出來店枣,可以專注于代碼本身的邏輯。說白了就是有 Lazy Load 的特性闷旧,用到某模塊時钧唐,SeaJS 才會去加載模塊的 JS 文件。我們可以按功能劃分多個模塊该园,觸發(fā)模塊功能時里初,SeaJS 先加載功能模塊的文件,然后執(zhí)行相應的功能淮阐。
這個 SeaJS 擁有的特性刁品,初看非常吸引人,它可以說是新定義了一種開發(fā)和管理 JavaScript 文件的模式状您。遵循這個模式镀裤,你會享受起 JavaScript 的開發(fā)暑劝。
實踐證明,它也的確可以使 JavaScript 模塊化幕垦,根據功能劃分模塊傅联,每個模塊對應一個 JavaScript 文件蒸走,當執(zhí)行到模塊的功能,或者你需要加載模塊時该溯,模塊才會被下載别惦,同時不會造成重復下載。這一切看起來如此的合理氯庆,如此的順暢。仁讨。粒督。屠橄。闰挡。
但是在使用后發(fā)現(xiàn)了一些問題:由于當時開發(fā)的網站功能相對簡單,JavaScript 文件并不是非常大溪北,過多的模塊之拨,反而會導致總加載的時間變多了咧叭。
由于是 Lazy Load 特性,不適合的模塊劃分導致網站出現(xiàn)反應慢的現(xiàn)象吉挣,原因是得先加載模塊的文件睬魂,才能執(zhí)行模塊的功能镀赌。當網絡情況不好時,該現(xiàn)象表現(xiàn)的更為嚴重:砀帧M谩歇盼!
可以說,問題出在了對新技術的不了解上伯复,從而出現(xiàn)了問題,預期是 SeaJS 可以處理 JavaScript 優(yōu)化的問題侍匙,因為它具有避免加載不必要模塊的功能叮雳,結果反而南轅北轍帘不。
總結
雖然嘗試出現(xiàn)了問題,但是储狭,收獲也是巨大的辽狈,簡單來說就是以下兩點:
1)因地制宜呛牲,根據實際需要使用模塊化技術侈净,切勿跟風技術,在自己沒有完全掌握時元扔,謹慎用于產品中旋膳。
2)模塊如果是懶加載的,粒度不能太小擅羞,也就是模塊不能太小义图。
根據大功能來劃分模塊也是一個不錯的嘗試碱工。
筆者嘗試將所有模塊劃分為基礎模塊和功能模塊奏夫,基礎模塊包括頁面頭部酗昼,尾部相關的公共部分梳猪,功能模塊則根據前后臺劃分春弥,前臺部分,又根據具體的頁面來劃分惕稻,能合并到一起的竖共,就合并成一個模塊,增加粒度俺祠。結果 JavaScript 文件減少,也達到了預期的效果借帘。
從實際體驗來看蜘渣,對于流量不大的網站來說,沒有必要使用懶加載 JavaScript 的相關技術肺然,因為本身 JavaScript 文件就不是非常大蔫缸。因此在網頁加載時,就可以先加載所需要的模塊际起。避免不必要的延遲。
三.JavaScript 的位置問題
這一部分街望,我們來說說JavaScript 的位置問題對網頁網站性能的影響校翔。
為什么要考慮位置問題?
其實不管是 CSS 還是 JavaScript灾前,都需要考慮位置的問題防症,因為 HTML 的渲染和加載順序是從上往下,也就是如果前面插入了 JavaScript 的引用哎甲,那么必須等到這個 JavaScript 下載完畢才會渲染后續(xù)的部分蔫敲。
因此 JavaScript 的插入位置就成為一個值得考慮的問題,因為不適合的位置可能引起渲染的延遲等炭玫,造成不好的用戶體驗奈嘿。
傳統(tǒng)方案帶來的問題和思考
CSS 放在頭部,JavaScript 放在尾部吞加,這是傳統(tǒng)的經驗裙犹,它的好處是可以讓頁面優(yōu)先渲染, 從而頁面可以快速顯示尽狠。
但有事實往往沒有我們預想的那么美好。
有的時候會出現(xiàn)這么一種情況:當頁面已經渲染完畢時伯诬,我們立刻去使用網站的功能晚唇,但很多時候功能按鈕會沒有反應。原因也很簡單盗似,就是 JavaScript 放在頁面的尾部哩陕,還沒來得及加載。赫舒。悍及。。
這就糾結了接癌。心赶。。缺猛。
兩種 JavaScript 放置方式缨叫,一種放在頭部,一種放在尾部(暫時忽略部分放在頭部荔燎,部分放在尾部的方式)耻姥,一個犧牲了渲染速度,一個犧牲了用戶體驗有咨。所以很多時候 js 的問題我們需要做權衡琐簇。
對一般的小型網站來說,用戶體驗問題要遠遠大于頁面渲染的問題座享,就比如上文提到的那種功能按鈕不可用的情況婉商。而且,如果 JavaScript 不是很大的話渣叛,放在頭部就很好丈秩,既不會有太久的頁面空白,也能讓其優(yōu)先加載诗箍,二者得到了很好的平衡癣籽。
因此,很多經驗上的東西并不是絕對的滤祖,一定要根據實際的情況筷狼,包括功能特點、服務器網絡情況等來綜合考慮匠童。
為此埂材,筆者寫下一個自認為較為合理的位置選擇方案,僅供參考汤求。
圖 1. 判斷 JavaScript 放置位置決策表
從上面的分類介紹俏险,我們也可以看出严拒,將功能代碼按類型歸類到不同的 JavaScript 文件是多么的重要,比如應該放頭部和應該放尾部的代碼竖独,最好不要合并在一起,不要等到出問題要優(yōu)化的時候再去整理和重構裤唠,這樣會增加很多不必要的工作量。
這不僅僅是為自己工作負責莹痢,也是為后面要讀你代碼的新人負責种蘸。養(yǎng)成好的設計編碼習慣,也是技術積累的一部分竞膳。最后再根據 JavaScript 文件的功能類型航瞭,來決定是放在頁面的頭部還是尾部。
四.怎樣確定是不是 JavaScript 的問題坦辟?
這個問題在之前的前端高性能優(yōu)化(一)刊侯、(二)中也都簡單的說過,之所以在這再次提及是因為確實覺得這個工具用著很舒服锉走。
沒錯滨彻,就是舒服。
隨著信息爆炸時代的到來挪蹭,網站本身性能也深刻影響著公司的形象疮绷、利益等問題。但是大多數前端測試工具都太碎片化嚣潜,沒有辦法針對多個使用場景,而且很多都是像 yslow 這樣簡單打個分椅贱,也不是真實的用戶體驗懂算。前一段時間在網上找到了一款前端性能優(yōu)化分析工具——Browser Insight,里面的功能相當全面庇麦,而且可以針對多個使用場景计技,包括:PC端,移動微信山橄,移動瀏覽器垮媒,移動webview,還是真實的用戶體驗航棱,也就是說睡雇,用戶訪問你的網頁是什么樣的,從這個工具中體現(xiàn)出的就是什么樣子的饮醇。
基于 JavaScript 這個維度 Bi 做的也是相當豐富了它抱。
首先是腳本錯誤板塊。Bi 里面可以從不同的時間維度查看被監(jiān)控頁面出現(xiàn)過的腳本錯誤朴艰,具體信息包括:發(fā)生時間观蓄、設備類型混移、報錯的瀏覽器及其版本號、錯誤堆棧信息都可以看到侮穿,不論是線上還是線下測試或者頁面維護都是夠用了歌径。
不但能看到時間、系統(tǒng)亲茅、瀏覽器等回铛,還可以具體定位到出錯的代碼行,這個確實很方便芯急。
圖 2.Bi 腳本錯誤
其次是頁面響應時間板塊勺届,這個算是意外的收獲了。通過響應時間板塊里面的慢加載追蹤娶耍,可以看到本次慢加載的頁面資源加載情況免姿,然后我們就知道該優(yōu)化哪個頁面的哪些 js 、css榕酒、img等胚膊。
圖 3.Bi 資源列表-時序圖
五.前端優(yōu)化?用戶體驗想鹰?
各位看客紊婉,如果你真能堅持看到這里,是否會覺得這篇更像解決用戶體驗問題的文章?但是講心里話辑舷,前端優(yōu)化的最終目的喻犁,難道不是為了改善用戶體驗嗎?
任何基于用戶體驗的方案何缓,都可以叫前端優(yōu)化技術肢础。
不管使用多么好的機器、多么高的技術碌廓,響應速度問題總是避免不了的传轰,因此糾結于什么技術來解決是不實際的。但是有一款好的工具谷婆,使用一些小技巧慨蛙,也可以改善用戶等待的體驗。
比如纪挎,我們?yōu)槊總€非 _target 的超鏈接或者表單的點擊期贫,添加點擊事件處理,處理邏輯也很簡單廷区,就是設置 3 秒超時唯灵,顯示等待對話框。如果在 3 秒內頁面發(fā)生跳轉隙轻,那么這個等待對話框就不會出現(xiàn)埠帕,否則會彈出提示用戶等待垢揩,從而及時的將響應反饋給用戶,減少用戶空白等待時間敛瓷。