1. 程式人生 > >AMP,來自 Google 的移動頁面優化方案

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 就必須引入以下檔案(必須要有 asynccustom-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 時間對比統計,可以看到明顯的變化:

dom ready time

將圖片、視訊等標籤和第三方功能換成 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--

提醒:本文最後更新於 602 天前,文中所描述的資訊可能已發生改變,請謹慎使用。