AMP,來自 Google 的移動頁面優化方案
提醒:本文最後更新於 602 天前,文中所描述的資訊可能已發生改變,請謹慎使用。
更新:本站正文頁已於 2017-03-08 上線 AMP 版,將 URL 中的
/post/
改為/amp/post/
即可。例如這是本文的 AMP 版:https://imququ.com/amp/post/amp-project.html。
Web 效能優化(Web Performance Optimization,WPO)是一個老生常談的話題,我也寫過很多關於「效能優化」的文章。最近 Google 某個團隊推出了一項名為 Accelerated Mobile Pages(AMP)的技術,號稱能大大加快移動端頁面呈現速度,提高整體體驗。本文就帶大家認識一下這項新技術。
AMP 介紹
Accelerated Mobile Pages(官網、GitHub),直譯成中文是「加速的移動頁面」的意思。根據官方說明,AMP 在 Speed Index(首屏展現時間平均值)測試中,效能有 15% ~ 85% 的提升,測試是在模擬 3G 網路環境並模擬 Nexus 5 的條件下完成(詳情)。
AMP 如何讓頁面效能大幅提升暫且擱置一邊,先來看看它是什麼。根據官網文件得知,AMP 主要由 AMP HTML、AMP Runtime 以及 AMP Components 三部分組成。
AMP HTML
AMP HTML 是 HTML 的子集,在 AMP HTML 中只允許使用有限的標籤。例如 <body>
<article>
這些標籤可以直接使用,沒有任何限制;有些標籤允許有限制的使用,例如 <meta>
標籤不能使用 http-equiv
屬性;而像 <img>
、<audio>
這樣的標籤需要替換為 <amp-img>
、<amp-audio>
等 AMP Components;更多的標籤如 <frame>
、<form>
不允許使用。
完整說明可以檢視官網的 建立 AMP HTML 頁面。以下是該文件中的 AMP HTML 示例:
<!doctype html>
<html amp lang="en">
<head>
<meta charset="utf-8">
<script async src="https://cdn.ampproject.org/v0.js"></script>
<title>Hello, AMPs</title>
<link rel="canonical" href="http://example.ampproject.org/article-metadata.html" />
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "NewsArticle",
"headline": "Open-source framework for publishing content",
"datePublished": "2015-10-07T12:02:41Z",
"image": [
"logo.jpg"
]
}
</script>
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
</head>
<body>
<h1>Welcome to the mobile web</h1>
</body>
</html>
可以看出,AMP HTML 與普通 HTML 並沒有什麼太大區別,將上面這段程式碼儲存為 .html
檔案,在瀏覽器中可以正常執行。下面簡單列舉一些格式上的要求:
- DTD 必須是:
<!doctype html>
; - 頂層標籤必須包含 AMP 屬性,如:
<html ⚡>
或<html amp>
(讓其他程式能方便地識別出這是 AMP HTML); - 必須在 HEAD 區域中放置
<link rel="canonical" href="$SOME_URL" />
標籤,用來指定該文件普通版本的 URL;如果只有一個版本,使用當前 URL 即可(告訴搜尋引擎,這是同一個頁面不同的版本,否則可能會被判作弊); - 必須將
<meta charset="utf-8">
放置在 HEAD 區域最開始的位置(實際上,普通 HTML 也應該這麼做); - 必須在 HEAD 區域包含這個 ViewPort:
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,minimal-ui">
; - 必須將
<script async src="https://cdn.ampproject.org/v0.js"></script>
作為 HEAD 區域最後的元素; - 必須在 HEAD 區域包含以下程式碼:
<style>body {opacity: 0}</style><noscript><style>body {opacity: 1}</style></noscript>
;
AMP Runtime
在上面的 AMP HTML 程式碼中,HEAD 區域最後外鏈引入的 JS 就是 AMP Runtime。AMP Runtime 提供對自定義元素(Custom Elements)的支援,負責協調資源的載入時機和優先順序,以及提供驗證器等除錯功能。
訪問 AMP HTML 時,在 URL 最後追加 #development=1
會開啟開發者模式。這時 AMP Runtime 會自動載入驗證器,並在控制檯顯示本頁不符合 AMP 規範的位置資訊。
AMP Components
AMP Components 是使用瀏覽器自定義元素(Custom Elements)實現的元件,用來替換 HTML 中預設的 <img>
和 <video>
等標籤,用來實現對資源的自定義載入策略;它也用於實現一些複雜的互動效果,如圖片輪播。AMP Components 分為兩類:
1)內建元件,包括:amp-img、amp-audio、amp-anim、amp-ad、amp-pixel、amp-video,在 AMP HTML 引入了 AMP Runtime 之後,這些內建元件就可以直接使用。
2)擴充套件元件,包括:amp-carousel、amp-lightbox、amp-iframe、amp-instagram、amp-twitter、amp-youtube。要使用擴充套件元件,需要在 AMP HTML 中引入該元件對應的檔案。例如要使用 amp-carousel 就必須引入以下檔案(必須要有 async
和 custom-element
屬性):
<script async custom-element="amp-carousel" src="https://cdn.ampproject.org/v0/amp-carousel-0.1.js"></script>
這裡有一個按照 AMP HTML 規範編寫的頁面,大家可以直接用瀏覽器開啟檢視:AMP 示例(注:為了保證國內開啟速度,我把 AMP JS 託管在了本地,實際上這麼做並不符合規範)。
AMP 剖析
定位:解決單一問題
經過前面對 AMP 的介紹,你一定會感到奇怪,為什麼 AMP HTML 有那麼多限制和約束,這樣閹割後的 HTML 還有什麼適用場景。實際上,AMP 只關注於一件事 —— 提高靜態頁面的效能。
這個「靜態」並不是指沒有服務端參與的頁面,而是指沒有複雜互動、以內容展現為主的資源頁,典型例子就是新聞詳情頁。現在的網站型別很多,遊戲類、視訊類、電商類等等,每一類網站都有著自己的特點,優化策略也各不相同,用一種方案去解決所有問題不切實際。所以 AMP 專案將關注點放在了更容易優化且效果最明顯的內容型頁面。
選型:純 web 技術方案
Web 優化有很多種方案,每種方案都有自己的適用範圍。有些收益很高的優化手段,存在這樣那樣的限制:例如針對具體業務邏輯所做的優化,很難通用化;部署 Google 的 PageSpeed 模組等服務端優化方案,使用成本很高;藉助客戶端所做的優化,如現在廣為流行的移動端 WebView 容器加速方案,優化效果侷限在指定 APP 內,甚至還會導致使用通用瀏覽器訪問速度更慢(這個話題很有意思,有機會以後再討論)。
以內容為主的新聞詳情頁,大部分效能消耗在圖片、視訊等媒體資源以及第三方功能如廣告、社會化元件的載入上。將這些內容替換為 AMP Components,避免資源預設被載入,再用 AMP Runtime 統一協調和管理,確實是一個通用化、低使用成本且能讓所有瀏覽器受益的折中方案。而且,AMP 方案不依賴任何特定的服務端或客戶端,可以將頁面直接託管在 CDN,進一步提高使用者訪問速度。
實現:資源排程與控制
瀏覽器對不同資源載入和預載入有自己的策略,對於預載入,我們有一些控制權,但總的看來這一塊對於開發者來說還是很不可控。例如瀏覽器預設會並行載入多張圖片,但在螢幕小、網速慢、效能差的手機上,序列由上到下載入圖片很可能體驗更好。
移動裝置在網路、CPU、記憶體等方面與 PC 差距很大,很多 PC 上可以忽略的問題,在移動端不得不重視起來。例如我們都知道圖片是非同步載入的,頁面觸發 DOMContentLoaded 事件並不需要等圖片載入完,但在移動端,大量圖片載入帶來效能開銷卻會大幅延後 DOMContentLoaded 時機。以下是我們在某個移動產品中,將圖片進行延遲載入處理後的 DOMContentLoaded 時間對比統計,可以看到明顯的變化:
將圖片、視訊等標籤和第三方功能換成 AMP Components 後,AMP Runtime 可以自動處理延遲載入、按需載入等邏輯,確保頁面首屏效能。為了避免延遲載入的資源引發頁面抖動,開發者必須給每個 AMP Components 都設定高寬屬性,每個 Components 都支援多種 layout 佈局,在 responsive
佈局下,元件會根據初始高寬比例自動調整大小。
另外,一些資源非常消耗效能,例如 gif 和 video,AMP Runtime 可以在它們處於不可見時銷燬元素,釋放資源。總之,使用了 AMP 方案,相當於將頁面資源託管給了 AMP Runtime 管理,一次修改就可以坐享後續所有策略升級帶來的效能提升。
觀點:很有借鑑意義
本文到這裡,差不多快要結束了。經過上面的介紹,大家對 AMP 專案應該有了一定的認識。最後談談我的看法:
AMP 專案對書寫程式碼設定了大量限制,例如所有資源只能託管給 AMP Runtime 載入;不允許使用 AMP Runtime、AMP Components 之外的 JS;不允許使用 inline JS;只能使用有限的 inline CSS 樣式;JS 和 Web Font 必須使用指定的 CDN 等等,這都是為後面的優化策略做準備。整體原理並不複雜,難點是配套設施的建立,以及如何說服網站主改造程式碼。不過,Google 後續很可能對使用了 AMP 的頁面提權,這樣一來大家就有動力了。
符合 AMP 規範的頁面不會比由 WPO 專家優化後的頁面更快,它是一個通用化的技術,肯定包含很多業務用不上的程式碼邏輯,也有很多優化手段它無法提供。但對於不知道如何 WPO 的網站來說,使用 AMP 則是一個非常不錯的選擇。
不過,我認為 AMP 很難直接用在國內專案中。首先,前面說過,AMP Runtime、Components 必須從 cdn.ampproject.org
載入;Web Font 必須從 fonts.googleapis.com
載入。這樣做的出發點是為了更可控,以及更好的在各網站之間共享快取,但是這些域名在國內很難訪問甚至直接被牆。其次,從目前 AMP 目前已有的擴充套件元件來看,instagram、twitter、youtube 這類國外媒體常用的服務在國內都無法使用,內建的 ad 元件也不符合國情。
但是,AMP 專案對我們進行移動 Web 優化仍然很有借鑑意義。實際上,控制資源載入、處理響應式元素避免頁面抖動、主動釋放資源等策略,我們在專案中都有自己的嘗試與經驗,但我們的方案要麼過分依賴服務端,要麼沒有抽象成通用模式,導致無法推廣到更多產品,這些都是後續可以努力的方向,而 AMP 規範和程式碼實現,將會是最好的參考資料。
--EOF--
發表於 2015-10-10 01:47:24 ,並被新增「 效能優化 、 Google 」標籤 ,最後修改於 2017-03-29 18:50:51 。檢視本文 Markdown 版本 »
提醒:本文最後更新於 602 天前,文中所描述的資訊可能已發生改變,請謹慎使用。