唯快不破:Web 應(yīng)用的 13 個優(yōu)化步驟
時過境遷,Web 應(yīng)用比以往任何時候都更具交互性。搞定性能可以幫助你極大地改善終端用戶的體驗。閱讀以下的技巧并學(xué)以致用,看看哪些可以用來改善延遲,渲染時間以及整體性能吧!

更快的 Web 應(yīng)用
優(yōu)化 Web 應(yīng)用是一項費勁的工作。Web 應(yīng)用不僅處于客戶端和服務(wù)器端的兩部分組件當中,通常來說也是由多種多樣的技術(shù)棧構(gòu)建而成:數(shù)據(jù)庫,后端組件(一般也是搭建在不同技術(shù)架構(gòu)之上的),以及前端(HTML + JavaScript + CSS + 轉(zhuǎn)譯器)。運行時也是變化多端的:iOS,Android,Chrome,F(xiàn)irefox,Edge。如果你曾經(jīng)工作在一個不同的單一龐大的平臺之上,通常情況下性能優(yōu)化只針對于單一目標(甚至只是目標的單一版本而已),但是現(xiàn)在的話你就可能會意識到任務(wù)復(fù)雜度要遠超于此。這就對了。但這兒也有一些通用的優(yōu)化指南可以大大優(yōu)化一個應(yīng)用。我們將會在接下來的章節(jié)中探討這些指南的內(nèi)容。
一份 Bing 的研究表明,頁面加載時間每增加 10ms,網(wǎng)站的年收入就會減少 25 萬美元。 ——?Rob Trace 和 David Walp,微軟高級程序經(jīng)理
過早優(yōu)化?
優(yōu)化最難的地方就是如何在開發(fā)生命周期中最適當?shù)臅r候去做優(yōu)化。Donald Knuth 有一句名言:「過早優(yōu)化乃萬惡之源」。這句話背后的原因非常簡單:因為一不小心就會浪費時間去優(yōu)化某個 1% 的地方,但是結(jié)果卻并不會對性能造成什么重大影響。與此同時,一些優(yōu)化還妨礙了可讀性或者是可維護性,甚至還會引入新的 Bug。換句話說,優(yōu)化不應(yīng)當被認為是「意味著得到應(yīng)用程序的最佳性能」,而是「探索優(yōu)化應(yīng)用的正確的方式,并得到最大的效益」。再換句話說,盲目的優(yōu)化可能會導(dǎo)致效率的丟失,而收益卻很小。在你應(yīng)用以下技巧的時候請將此銘記在心。你最好的朋友就是分析工具:找到你可以進行通過優(yōu)化獲得最大程度改善的性能點,而不用損害應(yīng)用開發(fā)的進程或者可維護性。
程序員們浪費了大量時間來思考,或者說是擔憂,他們的程序中非關(guān)鍵部分的運行速度。并且他們對于性能的這些嘗試,實際上卻對代碼的調(diào)試和維護有著非常消極的影響。我們應(yīng)當忘記那些不重要的性能影響,在 97% 的時間里都可以這么說:過早優(yōu)化乃萬惡之源。當然我們也不應(yīng)當在那關(guān)鍵的 3% 上放棄我們的機會。—— Donald Knuth
1. JavaScript 壓縮和模塊打包
JavaScript 應(yīng)用是以源碼形式進行分發(fā)的,而源碼解析的效率是要比字節(jié)碼低的。對于一小段腳本來說,區(qū)別可以忽略不計。但是對于更大型的應(yīng)用,腳本的大小會對應(yīng)用啟動時間有著負面的影響。事實上,寄期望于使用?WebAssembly?而獲得最大程度的改善,其中之一就是可以得到更快的啟動時間。
另一方面,模塊打包則用于將不同腳本打包在一起并放進同一文件。更少的 HTTP 請求和單個文件解析都可以減少加載時間。通常情況下,單獨一種工具就可以處理打包和壓縮。Webpack?就是其中之一。
示例代碼:
function?insert(i)?{ ????document.write("Sample?"?+?i);}for(var?i?=?0;?i?30;?++i)?{ ????insert(i);}
結(jié)果如下:
!function(r){function?t(o){if(e[o])return?e[o].exports;var?n=e[o]={exports:{},id:o,loaded:!1};return?r[o].call(n.exports,n,n.exports,t),n.loaded=!0,n.exports}var?e={};return?t.m=r,t.c=e,t.p="",t(0)}([function(r,t){function?e(r){document.write("Sample?"+r)}for(var?o=0;30>o;++o)e(o)}]);//#?sourceMappingURL=bundle.min.js.map
進一步打包
你也可以使用 Webpack 打包 CSS 文件以及合并圖片。這些特性都可以有助于改善啟動時間。研究一下?Webpack 文檔來做些測試吧!
2. 按需加載資源
資源(特別是圖片)的按需加載或者說惰性加載,可以有助于你的 Web 應(yīng)用在整體上獲得更好的性能。對于使用大量圖片的頁面來說惰性加載有著顯著的三個好處:
減少向服務(wù)器發(fā)出的并發(fā)請求數(shù)量(這就使得頁面的其他部分獲得更快的加載時間)
減少瀏覽器的內(nèi)存使用率(更少的圖片,更少的內(nèi)存)
減少服務(wù)器端的負載
大體上的理念就是只在必要的時候才去加載圖片或資源(如視頻),比如在第一次被顯示的時候,或者是在將要顯示的時候?qū)ζ溥M行加載。由于這種方式跟你建站的方式密切相關(guān),惰性加載的解決方案通常需要借助其他庫的插件或者擴展來實現(xiàn)。舉個例子,react-lazy-load?就是一個用于處理 React 惰性加載圖片的插件:
const?MyComponent?=?()?=>?( ??
一個非常好的實踐范例就像 Goggle Images 的搜索工具一樣。點擊前面的鏈接并且滑動頁面滾動條就可以看到效果了。
3. 在使用 DOM 操作庫時用上 array-ids
如果你正在使用?React,Ember,Angular?或者其他 DOM 操作庫,使用 array-ids(或者 Angular 1.x 中的 track-by 特性)非常有助于實現(xiàn)高性能,對于***???頁尤其如此。我們已經(jīng)在上一篇程序衡量標準的文章中看到這個特性的效果了:?More Benchmarks: Virtual DOM vs Angular 1 & 2 vs Mithril.js vs cito.js vs The Rest (Updated and Improved!)。
此特性背后的主要概念就是盡可能多地重用已有的節(jié)點。Array ids?使得 DOM 操作引擎可以「知道」在什么時候某個節(jié)點可以被映射到數(shù)組當中的某個元素。沒有?array-ids?或者track-by?的話,大部分庫都會進行重新排序而摧毀已有的節(jié)點并重新創(chuàng)建新的。這就非常損耗性能了。
4. 緩存
Caches?是用于存儲那些被頻繁存取的靜態(tài)數(shù)據(jù)的組件,便于隨后對于這個數(shù)據(jù)的請求可以更快地被響應(yīng),或者說請求方式更加高效。由于 Web 應(yīng)用是由很多可拆卸的部件組合而成,緩存就可以存在于架構(gòu)中的很多部分。舉例來說,緩存可以被放在動態(tài)內(nèi)容服務(wù)器和客戶端之間,就可以避免公共請求以減少服務(wù)器的負載,與此同時改善響應(yīng)時間。其他緩存可能被放置在代碼里,以優(yōu)化某些用于腳本存取的通用模式,還有些緩存可能被放置在數(shù)據(jù)庫或者是長運行進程之前。
簡而言之,在 Web 應(yīng)用中使用緩存是一種改善響應(yīng)時間和減少 CPU 使用的絕佳方式。難點就在于搞清楚哪里才是在架構(gòu)中存放緩存的地方。再一次,答案就是性能分析:常見的瓶頸在哪里?數(shù)據(jù)或者結(jié)果可緩存嗎?他們都太容易失效嗎?這都是一些棘手的問題,需要從原理上來一點一點回答。
緩存的使用在 Web 環(huán)境中富有創(chuàng)造性。比如,basket.js?就是一個使用Local Storage?來緩存應(yīng)用腳本的庫。所以你的 Web 應(yīng)用在第二次運行腳本的時候就可以幾乎瞬間加載了。
如今一個廣受歡迎的緩存服務(wù)就是亞馬遜的?CloudFront。CloudFront 就跟通常的內(nèi)容分發(fā)網(wǎng)絡(luò)(CDN)用途一樣,可以被設(shè)置作為動態(tài)內(nèi)容的緩存。
我們的一個讀者指出了一個非常重要的遺漏:圖片編碼優(yōu)化。PNGs 和 JPGs 在 Web 發(fā)布時都會使用次優(yōu)的設(shè)置進行編碼。通過改變編碼器和它的設(shè)置,對于需要大量圖片的網(wǎng)站來說可以獲得有效的改善。流行的解決方案包括?OptiPNG?和jpegtran。
A guide to PNG optimization?詳細描述了 OptiPNG 可以如何用于優(yōu)化 PNGs。
The man page for jpegtran?對它的一些特性提供了很好的介紹。
如果你發(fā)現(xiàn)這些指南相對于你的要求來說都太復(fù)雜了的話,這兒有一些在線網(wǎng)站可以提供優(yōu)化服務(wù)。也有一些像?RIOT?一樣的圖形化界面,非常有助于批量操作和結(jié)果檢查。
5. 啟用 HTTP/2
越來越多的瀏覽器都開始支持 HTTP/2。這可能聽起來沒有必要,但是 HTTP/2 為同一服務(wù)器的并發(fā)連接問題帶來了很多好處。換句話說,如果有很多小型資源需要加載(如果你打包過的話就沒有必要了),在延遲和性能方面 HTTP/2 秒殺 HTTP/1。試試?Akamai 的 HTTP/2 demo,可以在最新的瀏覽器中看到區(qū)別。
6. 應(yīng)用性能分析
性能分析是優(yōu)化任何應(yīng)用程序時的重要一步。就像介紹中所提到的那樣,盲目嘗試優(yōu)化應(yīng)用經(jīng)常會導(dǎo)致效率的浪費,微不足道的收益和更差的可維護性。執(zhí)行性能分析是識別你的應(yīng)用問題所在的一個重要步驟。
對于 Web 應(yīng)用來說,延遲時間是最大的抱怨之一,所以你需要確保數(shù)據(jù)的加載和顯示都盡可能得快。Chrome 提供了非常棒的性能分析工具。特別是 Chrome Dev Tools 中的時間線和網(wǎng)絡(luò)視圖都對于定位延遲問題有著很大的幫助
找到性能損耗的中心可以讓你有效率地達到優(yōu)化的目標。
對后端的性能分析會更加困難。通常情況下,確認一個耗費較多時間的請求可以讓你明確應(yīng)該優(yōu)先分析哪一個服務(wù)。對于后端的分析工具來說,則取決于所構(gòu)建的技術(shù)棧。
一個關(guān)于算法的注意事項
在大多數(shù)情況下,選擇一個更優(yōu)的算法,比圍繞著小成本中心所實現(xiàn)的具體優(yōu)化策略能夠獲得更大的收益。在某種程度上,CPU 和內(nèi)存分析應(yīng)該可以幫你找到大的性能瓶頸。當這些瓶頸跟編碼問題并不相關(guān)時,則是時候考慮考慮不同的算法了。
7. 使用負載均衡方案
8. 為了更快的啟動時間考慮一下同構(gòu)
9. 使用索引加速數(shù)據(jù)庫查詢
10. 使用更快的轉(zhuǎn)譯方案
11. 避免或最小化 JavaScript 和 CSS 的使用而阻塞渲染
12. 用于未來的一個建議:使用 service workers + 流
13. 圖片編碼優(yōu)化
擴展閱讀
你可以在下面的鏈接中閱讀更多信息,以及找到有助于優(yōu)化網(wǎng)站的工具:
Best Practices for Speeding up Your Website - Yahoo Developer Network
YSlow - a tool that checks for Yahoo's recommended optimizations
PageSpeed Insights - Google Developers
PageSpeed Tools - Google Developers
HTTP/2: The Long-Awaited Sequel
悄悄話:Auth0 中常見的優(yōu)化
我們是一個 Web 公司。就以這種身份來說,我們?yōu)槲覀兊幕A(chǔ)設(shè)施的某些部分部署了一些特定的優(yōu)化。舉例來說,在登錄頁面你可以發(fā)現(xiàn),在我們域名的 /learn 路徑下(比如,登錄頁面的單點登錄),我們采用了一種特別的優(yōu)化:為了方便我們使用 CMS 來創(chuàng)建每篇文章。因為文章都沒有中心索引,但是為了能夠被搜索引擎發(fā)現(xiàn),使用了?webtask?的爬蟲來預(yù)渲染每個頁面并生成了一個靜態(tài)版本然后上傳到我們 CDN。這減少了我們在服務(wù)器端上的壓力,因為無須為每個訪客都生成動態(tài)的服務(wù)器端內(nèi)容。與此同時還改善了延遲(并且隔離了我們發(fā)現(xiàn)與 CMS 相關(guān)的安全問題)。
對于文檔部分,我們正在使用同構(gòu) JavaScript,這讓我們獲得了非常棒的啟動時間,并且使我們的后端和前端團隊能夠輕松集成。
結(jié)論
由于應(yīng)用程序變得越來越大和越來越復(fù)雜,性能優(yōu)化對于 Web 開發(fā)來說正在變得越來越重要。在做出任何值得的時間和潛在的未來成本的優(yōu)化嘗試時,有針對性的改進都是必不可少的。Web 應(yīng)用程序早已突破了大多數(shù)靜態(tài)內(nèi)容的邊界,學(xué)習(xí)常見模式進行優(yōu)化則是令人愉悅的應(yīng)用和完全不可用的應(yīng)用之間最大的區(qū)別(這是讓你的訪客留下來的長遠之計!)。沒有什么規(guī)則是絕對的,但是:性能分析和研究特定軟件技術(shù)棧的錯綜復(fù)雜之處,是找出如何優(yōu)化它的唯一方式。你曾經(jīng)發(fā)現(xiàn)過對你的應(yīng)用產(chǎn)生巨大影響的其他建議嗎?請留言讓我們知道。Hack on!
轉(zhuǎn)自:https://zhuanlan.zhihu.com/p/21417465?refer=no-backend
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔相應(yīng)法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔相應(yīng)法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。