優化 Web 應用是一項費勁的工作。 Web 應用不僅處於用戶端和伺服器端的兩部分元件當中, 通常來說也是由多種多樣的技術棧構建而成:資料庫,
一份 Bing 的研究表明, 頁面載入時間每增加 10ms, 網站的年收入就會減少 25 萬美元。 —— Rob Trace 和 David Walp, 微軟高級程式經理
過早優化?
優化最難的地方就是如何在開發生命週期中最適當的時候去做優化。 Donald Knuth 有一句名言:「過早優化乃萬惡之源」。
程式師們浪費了大量時間來思考, 或者說是擔憂,
1. JavaScript 壓縮和模組打包
javascript 應用是以源碼形式進行分發的, 而源碼解析的效率是要比位元組碼低的。 對於一小段腳本來說, 區別可以忽略不計。 但是對於更大型的應用, 腳本的大小會對應用啟動時間有著負面的影響。 事實上, 寄期望於使用 WebAssembly 而獲得最大程度的改善, 其中之一就是可以得到更快的啟動時間。
另一方面, 模組打包則用於將不同腳本打包在一起並放進同一檔。
示例代碼:
function insert(i) {
document.write("Sample " + i);
}
for(var i = 0; i
insert(i);
}
結果如下:
!function(r){function t(o){if(e[o])return e[o].exports;var n=e[o]={exports:{},id:o,loaded:!1};returnr[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 應用在整體上獲得更好的性能。 對於使用大量圖片的頁面來說惰性載入有著顯著的三個好處:
減少向伺服器發出的併發請求數量(這就使得頁面的其他部分獲得更快的載入時間)
減少流覽器的記憶體使用率(更少的圖片, 更少的記憶體)
減少伺服器端的負載
大體上的理念就是只在必要的時候才去載入圖片或資源(如視頻),
const MyComponent = () => (
Scroll to load images.
(...)
一個非常好的實踐範例就像 Goggle Images 的搜索工具一樣。點擊前面的連結並且滑動頁面捲軸就可以看到效果了。
3. 在使用 DOM 操作庫時用上 array-ids
如果你正在使用 React,Ember,Angular 或者其他 DOM 操作庫,使用 array-ids(或者 Angular 1.x 中的 track-by 特性)非常有助於實現高性能,對於動態網頁尤其如此。
這裡寫圖片描述
此特性背後的主要概念就是盡可能多地重用已有的節點。Array ids 使得 DOM 操作引擎可以「知道」在什麼時候某個節點可以被映射到陣列當中的某個元素。沒有 array-ids 或者 track-by 的話,大部分庫都會進行重新排序而摧毀已有的節點並重新創建新的。這就非常損耗性能了。
4. 緩存
Caches 是用於存儲那些被頻繁存取的靜態資料的元件,便於隨後對於這個資料的請求可以更快地被回應,或者說請求方式更加高效。由於 Web 應用是由很多可拆卸的部件組合而成,緩存就可以存在於架構中的很多部分。舉例來說,緩存可以被放在動態內容伺服器和用戶端之間,就可以避免公共請求以減少伺服器的負載,與此同時改善回應時間。其他緩存可能被放置在代碼裡,以優化某些用於腳本存取的通用模式,還有些緩存可能被放置在資料庫或者是長運行進程之前。
簡而言之,在 Web 應用中使用緩存是一種改善回應時間和減少 CPU 使用的絕佳方式。難點就在於搞清楚哪裡才是在架構中存放緩存的地方。再一次,答案就是性能分析:常見的瓶頸在哪裡?資料或者結果可緩存嗎?他們都太容易失效嗎?這都是一些棘手的問題,需要從原理上來一點一點回答。
緩存的使用在 Web 環境中富有創造性。比如,basket.js 就是一個使用Local Storage 來緩存應用腳本的庫。所以你的 Web 應用在第二次運行腳本的時候就可以幾乎瞬間載入了。
如今一個廣受歡迎的緩存服務就是亞馬遜的 CloudFront。CloudFront 就跟通常的內容分發網路(CDN)用途一樣,可以被設置作為動態內容的緩存。
5. 啟用 HTTP/2
越來越多的流覽器都開始支持 HTTP/2。這可能聽起來沒有必要,但是 HTTP/2 為同一伺服器的併發連接問題帶來了很多好處。換句話說,如果有很多小型資源需要載入(如果你打包過的話就沒有必要了),在延遲和性能方面 HTTP/2 秒殺 HTTP/1。試試 Akamai 的 HTTP/2 demo,可以在最新的流覽器中看到區別。
這裡寫圖片描述
6. 應用性能分析
性能分析是優化任何應用程式時的重要一步。就像介紹中所提到的那樣,盲目嘗試優化應用經常會導致效率的浪費,微不足道的收益和更差的可維護性。執行性能分析是識別你的應用問題所在的一個重要步驟。
對於 Web 應用來說,延遲時間是最大的抱怨之一,所以你需要確保資料的載入和顯示都盡可能得快。Chrome 提供了非常棒的性能分析工具。特別是 Chrome Dev Tools 中的時間線和網路視圖都對於定位延遲問題有著很大的幫助:
這裡寫圖片描述
時間線視圖可以幫忙找到執行時間較長的操作。
這裡寫圖片描述
網路視圖可以説明識別出額外的由緩慢請求導致的延遲或對於某一端點的串列訪問。
正確分析的話,記憶體則是另一塊可能獲得收益的部分。如果你正在運行著一個擁有很多虛擬元素的頁面(龐大的動態表格)或者可互動式的元素(比如遊戲),記憶體優化可以獲得更少的卡頓和更高的幀率。
找到性能損耗的中心可以讓你有效率地達到優化的目標。
對後端的性能分析會更加困難。通常情況下,確認一個耗費較多時間的請求可以讓你明確應該優先分析哪一個服務。對於後端的分析工具來說,則取決於所構建的技術棧。
一個關於演算法的注意事項
在大多數情況下,選擇一個更優的演算法,比圍繞著小成本中心所實現的具體優化策略能夠獲得更大的收益。在某種程度上,CPU 和記憶體分析應該可以幫你找到大的性能瓶頸。當這些瓶頸跟編碼問題並不相關時,則是時候考慮考慮不同的演算法了。
7. 使用負載均衡方案
我們在之前討論緩存的時候簡要提到了內容分發網路(CDNs)。把負載分配到不同的伺服器(甚至於不同的地理區域)可以給你的用戶提供更好的延遲時間,但是這條路還很漫長,特別是在處理很多的併發連接的時候。
負載均衡就跟使用某個 round-robin(迴圈)解決方案一樣簡單,可以基於一個 nginx 反向代理 ,或者基於一個成熟的分散式網路,比如 Cloudflare 或者 Amazon CloudFront。
這裡寫圖片描述
以上的圖來自於 Citrix。 為了使負載均衡真正有效,動態內容和靜態內容都應該被拆分成易於併發訪問的。換句話說,元素的串形訪問會削弱負載等化器以最佳形式進行分流的能力。與此同時,對於資源的併發訪問可以改善啟動時間。
雖然負載均衡可能會很複雜。對最終一致性演算法不友好的資料模型,或者緩存都會讓事情更加困難。幸運的是,大多數應用對於已簡化的資料集都只需要保證高層次的一致性即可。如果你的應用程式沒有這樣設計的話,就有必要重構一下了。
8. 為了更快的啟動時間考慮一下同構 JavaScript
var React = require('react/addons');
var ReactApp = React.createFactory(require('../components/ReactApp').ReactApp);
module.exports = function(app) {
app.get('/', function(req, res){
// React.renderToString takes your component
// and generates the markup
var reactHtml = React.renderToString(ReactApp({}));
// Output html rendered by react
// console.log(myAppHtml);
res.render('index.ejs', {reactOutput: reactHtml});
});
};
Meteor.js 對於用戶端和伺服器端的 JavaScript 混用有著非常棒的支持。
if (Meteor.isClient) {
Template.hello.greeting = function () {
return "Welcome to myapp.";
};
Template.hello.events({
'click input': function () {
// template data, if any, is available in 'this'
if (typeof console !== 'undefined')
console.log("You pressed the button");
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
但是,為了支援伺服器端渲染,需要像 meteor-ssr 這樣的外掛程式 . 如果你有複雜的或者中等大小的應用需要支援同構部署,試試這個,你可能會感到驚訝的。
9. 使用索引加速資料庫查詢
如果你需要解決資料庫查詢耗費大量時間的問題(分析你的應用看看是否是這種情況!),是時候找出加速資料庫的方法了。每個資料庫和資料模型都有自己的權衡。資料庫優化在每一方面都是一個主題:資料模型,資料庫類型,具體實現方案,等等。提速可能不是那麼的簡單。但是這兒有個建議,可能可以對某些資料庫有所説明:索引。索引是一個過程,即資料庫所創建的快速訪問資料結構,從內部映射到鍵(在關聯式資料庫中的列),可以提高檢索相關資料的速度。大多數現代資料庫都支援索引。索引並不是文檔型資料庫(比如 MongoDB)所獨有的,也包括關係型數據庫(比如PostgreSQL)。
為了使用索引來優化你的查詢,你將需要研究一下應用程式的訪問模式:什麼是最常見的查詢,在哪個鍵或列中執行搜索,等等。
10. 使用更快的轉譯方案
JavaScript 軟體技術棧一如既往的複雜。而改善語言本身的需求則又增加了複雜度。不幸地是,JavaScript 作為目標平臺又會被使用者的運行時所限制。儘管很多改進已經以 ECMAScript 2015(2016正在進行)的形式實現了,但是通常情況下,對用戶端代碼來說又不可能依賴於這個版本。這種趨勢促使了一系列的轉譯器:用於處理 ECMAScript 2015 代碼的工具和只使用 ECMAScript 5 結構實現其中所缺失的特性。與此同時,模組綁定和壓縮處理也已經被集成到這個生產過程中,被稱為為發佈而構建的代碼版本。這些工具可以轉化代碼,並且能夠以有限的方式影響到最終代碼的性能。Google 開發者 Paul Irish 花了一些時間來尋找這些轉譯方案會如何影響性能和最終代碼的大小。儘管大多數情況下收益會很小,但也值得在正式採用某個工具棧之前看看這些資料。對於大型應用程式來說,這種區別可能會影響重大。
11. 避免或最小化 JavaScript 和 CSS 的使用而阻塞渲染
JavaScript 和 CSS 資源都會阻塞頁面的渲染。通過採取某些的規則,你可以保證你的腳本和 CSS 被盡可能快速地處理,以便於流覽器能夠顯示你的網站內容。
在 CSS 的情況下這是非常重要的,所有的 CSS 規則都不能與特定媒體直接相關,規則只用於處理你準備在頁面上所顯示內容的優先順序。這可以通過使用 CSS 媒體查詢來實現。媒體查詢告訴流覽器,哪些 CSS 樣式表應用在某個特定的顯示媒體上。舉個例子,用於列印的某些規則可以被賦予比用於螢幕顯示更低的優先順序。
媒體查詢可以被設置成 標籤屬性:
輪到 JavaScript 了,關鍵就在於遵循某些用於內聯 JavaScript 的規則(比如內聯在 HTML 檔當中的代碼)。內聯 JavaScript 應該盡可能短,並將其放在不會阻塞頁面剩餘部分解析的地方。換句話說,被放在 HTML 樹中間的內聯 JavaScript 將會在這個地方阻塞解析器,並強制其等待直到腳本被執行完畢。如果在 HTML 檔中隨意放了一些大的代碼塊或者很多小的代碼塊,對於性能來說這會成為性能殺手。內聯可以有效減少額外對於某些特定腳本的網路請求。但是對於重複使用的腳本或者大的代碼塊來說,這個好處就可以忽略不計了。
防止 JavaScript 阻塞解析器和渲染器的一種方法就是將
12. 用於未來的一個建議:使用 service workers + 流
Jake Archibald 最近的一篇博文詳細描述了一種有趣的技術,可以用於加速渲染時間:將 service workers 和流結合起來。結果非常令人嘆服:
不幸的是這個技術所需要的 APIs 都還不穩定,這也是為什麼這是一種有趣的概念但現在還沒有真正被應用的原因。這個想法的主旨就是在網站和用戶端之間放置一個 service worker。這個 service worker 可以在獲取缺失資訊的同時緩存某些資料(比如 header 和一些不會經常改變的東西)。缺失的內容就可以盡可能快速地流向被渲染的頁面。
https://www.youtube.com/watch?v=Cjo9iq8k-bc
13. 圖片編碼優化
圖片編碼優化。PNGs 和 JPGs 在 Web 發佈時都會使用次優的設置進行編碼。通過改變編碼器和它的設置,對於需要大量圖片的網站來說可以獲得有效的改善。流行的解決方案包括 OptiPNG 和jpegtran。
A guide to PNG optimization(http://optipng.sourceforge.net/pngtech/optipng.html) 詳細描述了 OptiPNG 可以如何用於優化 PNGs。
The man page for jpegtran(http://linux.die.net/man/1/jpegtran) 對它的一些特性提供了很好的介紹。
如果你發現這些指南相對於你的要求來說都太複雜了的話,這兒有一些線上網站可以提供優化服務。也有一些像 RIOT 一樣的圖形化介面,非常有助於批量操作和結果檢查。
結論
由於應用程式變得越來越大和越來越複雜,性能優化對於 Web 開發來說正在變得越來越重要。在做出任何值得的時間和潛在的未來成本的優化嘗試時,有針對性的改進都是必不可少的。Web 應用程式早已突破了大多數靜態內容的邊界,學習常見模式進行優化則是令人愉悅的應用和完全不可用的應用之間最大的區別(這是讓你的訪客留下來的長遠之計!)。沒有什麼規則是絕對的,但是:性能分析和研究特定軟體技術棧的錯綜複雜之處,是找出如何優化它的唯一方式。
(...)
一個非常好的實踐範例就像 Goggle Images 的搜索工具一樣。點擊前面的連結並且滑動頁面捲軸就可以看到效果了。
3. 在使用 DOM 操作庫時用上 array-ids
如果你正在使用 React,Ember,Angular 或者其他 DOM 操作庫,使用 array-ids(或者 Angular 1.x 中的 track-by 特性)非常有助於實現高性能,對於動態網頁尤其如此。
這裡寫圖片描述
此特性背後的主要概念就是盡可能多地重用已有的節點。Array ids 使得 DOM 操作引擎可以「知道」在什麼時候某個節點可以被映射到陣列當中的某個元素。沒有 array-ids 或者 track-by 的話,大部分庫都會進行重新排序而摧毀已有的節點並重新創建新的。這就非常損耗性能了。
4. 緩存
Caches 是用於存儲那些被頻繁存取的靜態資料的元件,便於隨後對於這個資料的請求可以更快地被回應,或者說請求方式更加高效。由於 Web 應用是由很多可拆卸的部件組合而成,緩存就可以存在於架構中的很多部分。舉例來說,緩存可以被放在動態內容伺服器和用戶端之間,就可以避免公共請求以減少伺服器的負載,與此同時改善回應時間。其他緩存可能被放置在代碼裡,以優化某些用於腳本存取的通用模式,還有些緩存可能被放置在資料庫或者是長運行進程之前。
簡而言之,在 Web 應用中使用緩存是一種改善回應時間和減少 CPU 使用的絕佳方式。難點就在於搞清楚哪裡才是在架構中存放緩存的地方。再一次,答案就是性能分析:常見的瓶頸在哪裡?資料或者結果可緩存嗎?他們都太容易失效嗎?這都是一些棘手的問題,需要從原理上來一點一點回答。
緩存的使用在 Web 環境中富有創造性。比如,basket.js 就是一個使用Local Storage 來緩存應用腳本的庫。所以你的 Web 應用在第二次運行腳本的時候就可以幾乎瞬間載入了。
如今一個廣受歡迎的緩存服務就是亞馬遜的 CloudFront。CloudFront 就跟通常的內容分發網路(CDN)用途一樣,可以被設置作為動態內容的緩存。
5. 啟用 HTTP/2
越來越多的流覽器都開始支持 HTTP/2。這可能聽起來沒有必要,但是 HTTP/2 為同一伺服器的併發連接問題帶來了很多好處。換句話說,如果有很多小型資源需要載入(如果你打包過的話就沒有必要了),在延遲和性能方面 HTTP/2 秒殺 HTTP/1。試試 Akamai 的 HTTP/2 demo,可以在最新的流覽器中看到區別。
這裡寫圖片描述
6. 應用性能分析
性能分析是優化任何應用程式時的重要一步。就像介紹中所提到的那樣,盲目嘗試優化應用經常會導致效率的浪費,微不足道的收益和更差的可維護性。執行性能分析是識別你的應用問題所在的一個重要步驟。
對於 Web 應用來說,延遲時間是最大的抱怨之一,所以你需要確保資料的載入和顯示都盡可能得快。Chrome 提供了非常棒的性能分析工具。特別是 Chrome Dev Tools 中的時間線和網路視圖都對於定位延遲問題有著很大的幫助:
這裡寫圖片描述
時間線視圖可以幫忙找到執行時間較長的操作。
這裡寫圖片描述
網路視圖可以説明識別出額外的由緩慢請求導致的延遲或對於某一端點的串列訪問。
正確分析的話,記憶體則是另一塊可能獲得收益的部分。如果你正在運行著一個擁有很多虛擬元素的頁面(龐大的動態表格)或者可互動式的元素(比如遊戲),記憶體優化可以獲得更少的卡頓和更高的幀率。
找到性能損耗的中心可以讓你有效率地達到優化的目標。
對後端的性能分析會更加困難。通常情況下,確認一個耗費較多時間的請求可以讓你明確應該優先分析哪一個服務。對於後端的分析工具來說,則取決於所構建的技術棧。
一個關於演算法的注意事項
在大多數情況下,選擇一個更優的演算法,比圍繞著小成本中心所實現的具體優化策略能夠獲得更大的收益。在某種程度上,CPU 和記憶體分析應該可以幫你找到大的性能瓶頸。當這些瓶頸跟編碼問題並不相關時,則是時候考慮考慮不同的演算法了。
7. 使用負載均衡方案
我們在之前討論緩存的時候簡要提到了內容分發網路(CDNs)。把負載分配到不同的伺服器(甚至於不同的地理區域)可以給你的用戶提供更好的延遲時間,但是這條路還很漫長,特別是在處理很多的併發連接的時候。
負載均衡就跟使用某個 round-robin(迴圈)解決方案一樣簡單,可以基於一個 nginx 反向代理 ,或者基於一個成熟的分散式網路,比如 Cloudflare 或者 Amazon CloudFront。
這裡寫圖片描述
以上的圖來自於 Citrix。 為了使負載均衡真正有效,動態內容和靜態內容都應該被拆分成易於併發訪問的。換句話說,元素的串形訪問會削弱負載等化器以最佳形式進行分流的能力。與此同時,對於資源的併發訪問可以改善啟動時間。
雖然負載均衡可能會很複雜。對最終一致性演算法不友好的資料模型,或者緩存都會讓事情更加困難。幸運的是,大多數應用對於已簡化的資料集都只需要保證高層次的一致性即可。如果你的應用程式沒有這樣設計的話,就有必要重構一下了。
8. 為了更快的啟動時間考慮一下同構 JavaScript
var React = require('react/addons');
var ReactApp = React.createFactory(require('../components/ReactApp').ReactApp);
module.exports = function(app) {
app.get('/', function(req, res){
// React.renderToString takes your component
// and generates the markup
var reactHtml = React.renderToString(ReactApp({}));
// Output html rendered by react
// console.log(myAppHtml);
res.render('index.ejs', {reactOutput: reactHtml});
});
};
Meteor.js 對於用戶端和伺服器端的 JavaScript 混用有著非常棒的支持。
if (Meteor.isClient) {
Template.hello.greeting = function () {
return "Welcome to myapp.";
};
Template.hello.events({
'click input': function () {
// template data, if any, is available in 'this'
if (typeof console !== 'undefined')
console.log("You pressed the button");
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
但是,為了支援伺服器端渲染,需要像 meteor-ssr 這樣的外掛程式 . 如果你有複雜的或者中等大小的應用需要支援同構部署,試試這個,你可能會感到驚訝的。
9. 使用索引加速資料庫查詢
如果你需要解決資料庫查詢耗費大量時間的問題(分析你的應用看看是否是這種情況!),是時候找出加速資料庫的方法了。每個資料庫和資料模型都有自己的權衡。資料庫優化在每一方面都是一個主題:資料模型,資料庫類型,具體實現方案,等等。提速可能不是那麼的簡單。但是這兒有個建議,可能可以對某些資料庫有所説明:索引。索引是一個過程,即資料庫所創建的快速訪問資料結構,從內部映射到鍵(在關聯式資料庫中的列),可以提高檢索相關資料的速度。大多數現代資料庫都支援索引。索引並不是文檔型資料庫(比如 MongoDB)所獨有的,也包括關係型數據庫(比如PostgreSQL)。
為了使用索引來優化你的查詢,你將需要研究一下應用程式的訪問模式:什麼是最常見的查詢,在哪個鍵或列中執行搜索,等等。
10. 使用更快的轉譯方案
JavaScript 軟體技術棧一如既往的複雜。而改善語言本身的需求則又增加了複雜度。不幸地是,JavaScript 作為目標平臺又會被使用者的運行時所限制。儘管很多改進已經以 ECMAScript 2015(2016正在進行)的形式實現了,但是通常情況下,對用戶端代碼來說又不可能依賴於這個版本。這種趨勢促使了一系列的轉譯器:用於處理 ECMAScript 2015 代碼的工具和只使用 ECMAScript 5 結構實現其中所缺失的特性。與此同時,模組綁定和壓縮處理也已經被集成到這個生產過程中,被稱為為發佈而構建的代碼版本。這些工具可以轉化代碼,並且能夠以有限的方式影響到最終代碼的性能。Google 開發者 Paul Irish 花了一些時間來尋找這些轉譯方案會如何影響性能和最終代碼的大小。儘管大多數情況下收益會很小,但也值得在正式採用某個工具棧之前看看這些資料。對於大型應用程式來說,這種區別可能會影響重大。
11. 避免或最小化 JavaScript 和 CSS 的使用而阻塞渲染
JavaScript 和 CSS 資源都會阻塞頁面的渲染。通過採取某些的規則,你可以保證你的腳本和 CSS 被盡可能快速地處理,以便於流覽器能夠顯示你的網站內容。
在 CSS 的情況下這是非常重要的,所有的 CSS 規則都不能與特定媒體直接相關,規則只用於處理你準備在頁面上所顯示內容的優先順序。這可以通過使用 CSS 媒體查詢來實現。媒體查詢告訴流覽器,哪些 CSS 樣式表應用在某個特定的顯示媒體上。舉個例子,用於列印的某些規則可以被賦予比用於螢幕顯示更低的優先順序。
媒體查詢可以被設置成 標籤屬性:
輪到 JavaScript 了,關鍵就在於遵循某些用於內聯 JavaScript 的規則(比如內聯在 HTML 檔當中的代碼)。內聯 JavaScript 應該盡可能短,並將其放在不會阻塞頁面剩餘部分解析的地方。換句話說,被放在 HTML 樹中間的內聯 JavaScript 將會在這個地方阻塞解析器,並強制其等待直到腳本被執行完畢。如果在 HTML 檔中隨意放了一些大的代碼塊或者很多小的代碼塊,對於性能來說這會成為性能殺手。內聯可以有效減少額外對於某些特定腳本的網路請求。但是對於重複使用的腳本或者大的代碼塊來說,這個好處就可以忽略不計了。
防止 JavaScript 阻塞解析器和渲染器的一種方法就是將
12. 用於未來的一個建議:使用 service workers + 流
Jake Archibald 最近的一篇博文詳細描述了一種有趣的技術,可以用於加速渲染時間:將 service workers 和流結合起來。結果非常令人嘆服:
不幸的是這個技術所需要的 APIs 都還不穩定,這也是為什麼這是一種有趣的概念但現在還沒有真正被應用的原因。這個想法的主旨就是在網站和用戶端之間放置一個 service worker。這個 service worker 可以在獲取缺失資訊的同時緩存某些資料(比如 header 和一些不會經常改變的東西)。缺失的內容就可以盡可能快速地流向被渲染的頁面。
https://www.youtube.com/watch?v=Cjo9iq8k-bc
13. 圖片編碼優化
圖片編碼優化。PNGs 和 JPGs 在 Web 發佈時都會使用次優的設置進行編碼。通過改變編碼器和它的設置,對於需要大量圖片的網站來說可以獲得有效的改善。流行的解決方案包括 OptiPNG 和jpegtran。
A guide to PNG optimization(http://optipng.sourceforge.net/pngtech/optipng.html) 詳細描述了 OptiPNG 可以如何用於優化 PNGs。
The man page for jpegtran(http://linux.die.net/man/1/jpegtran) 對它的一些特性提供了很好的介紹。
如果你發現這些指南相對於你的要求來說都太複雜了的話,這兒有一些線上網站可以提供優化服務。也有一些像 RIOT 一樣的圖形化介面,非常有助於批量操作和結果檢查。
結論
由於應用程式變得越來越大和越來越複雜,性能優化對於 Web 開發來說正在變得越來越重要。在做出任何值得的時間和潛在的未來成本的優化嘗試時,有針對性的改進都是必不可少的。Web 應用程式早已突破了大多數靜態內容的邊界,學習常見模式進行優化則是令人愉悅的應用和完全不可用的應用之間最大的區別(這是讓你的訪客留下來的長遠之計!)。沒有什麼規則是絕對的,但是:性能分析和研究特定軟體技術棧的錯綜複雜之處,是找出如何優化它的唯一方式。