小程式鼻祖 —— 在國內逐漸消亡的 PWA 可以帶給我們哪些啟示?

獨釣寒江雪發表於2022-04-20

  如果我說,我們要討論一個 2016 年被提出、2017 年落地、至今在國內仍可算籍籍無名的概念,你是不是會覺得這沒有什麼意義?

  網際網路發展了這麼久,我們記住了“Native App”、“小程式”、“快應用”、“App clips”、“Hybrid App”、“Web App”,似乎獨獨沒有 PWA,但 PWA 及其理念卻一直在推動著前端領域前進

PWA 是什麼?

  似乎 PWA 對很多人來說是如此陌生,PWA 對前端開發者來說卻又是無處不在。

身邊的 PWA

Lighthouse

  對前端開發者來說,Lighthouse 是一個很熟悉的網站效能診斷工具,在這裡,我們總是可以看到 PWA(Progressive Web App)的身影:

pwa_opt

PWA 書籍

  又或者,你曾無意間看到這些書籍或者資料:

開發者相關

  啊哈,這些,都沒看到過?那你總是訪問過Google Developers吧,或者總看見過這樣一個圖示:

google_dev

  可以認為這個圖示在哪裡,一個 PWA 應用就在哪裡,點選這個按鈕,可以將 PWA 應用安裝到桌面。於是,線上 IDE StackBlitz.com出現了,位元組內部使用的Goofy Studio PWA出現了:

stackblitz

谷歌的探索

  但是,動不動就講開發,真的太捲了,說說那些更有意思的 PWA 應用吧。

  2018 Google Chrome 開發者峰會上,Google 釋出了Squoosh,這是一個開源的圖片壓縮漸進式 Web 應用(PWA),它同時也是現代 Web 技術的一個實際展示,谷歌實驗室釋出 Squoosh 的主要目標是演示高階 web 應用程式如何利用現代技術在 web 瀏覽器中提供高效能的體驗。

squoosh

  PROXX是谷歌 Chrome 團隊推出的一款 JavaScript 遊戲。該專案展示瞭如何開發快速平滑的 Web 應用,這些應用在多種平臺和輸入裝置上提供了相近的使用者體驗。Proxx 專案的獨到之處在於它主要針對的是智慧功能機

智慧功能機是低價智慧機替代裝置,在印度和非洲廣為使用。相對於智慧機,智慧功能機的硬體非常簡單。它不支援觸控,螢幕相對較小,大多采用 240x320 解析度的 QVGA 屏,CPU 的處理能力也相對較弱。

proxx

  這是一款 JavaScript 遊戲掃雷遊戲,摸魚時可以玩兒玩兒,如果不幸被老闆撞見,你就說在研究 PWA 嘛

微博 Lite

  微博 Lite,我相信,這,應該是 PWA 離你最近的一次:

weibo

  我猜你一定不會問:既然 PWA 應用還是蠻廣泛的,那,它一定很強大吧?

  蒽,強不強大看看資料就知道了。

強大的生產力

  • 2017 年的一篇技術博文顯示,堪稱圖片版的 Twitter 的 Pinterest 將他們的移動網站重建為 PWA,核心參與度增加了 60%,使用者產生的廣告收入增加了 44%,花費的時間也增加了 40%;

compare_mobile_web

compare_pwa_app

  • 2016 年初 AliExpress 開始與 Google 團隊合作,推動 PWA 技術在 AliExpress 上的落地;結果是非常令人驚奇和滿意的。AliExpress 發現新使用者的轉換率增加了 104%。在 Safari 的轉化率也上升了 82%。現在使用者每次訪問的頁面數量是原先的兩倍,也大大提升了使用者瀏覽頁面的時間;
  • 類似這樣的成功案例數不勝數,為了方便你直接丟到老闆臉上,我梳理了這個圖 ?:

pwa_productivity

  我覺得你可以告訴他:這些不僅僅是數字,這些都是 PWA 的成功案例

  老闆說:這些和牆內的你我,距離能有多近?
  沒事,離我們最近的 PWA 應用將在你的手上誕生。

PWA 誕生的條件

  我們應該都深有體會,Native app 體驗確實很好,下載到手機上之後入口也方便。但它的優缺點很明顯:

native_app

  而 web 網頁開發成本低,網站更新時上傳最新的資源到伺服器即可,用手機帶的瀏覽器開啟就可以使用。但是除了體驗上比 Native app 還是差一些,還有一些明顯的缺點:

web_app

  在這些因素的推動下,Web 應用漸進式接近原生 App的概念 —— PWA 誕生了。

PWA 簡介

什麼是漸進式

  PWA 全稱為 Progressive Web App,中文譯為漸進式 Web APP,那麼,什麼是漸進式呢?我覺得漸進式有兩個層面的意思:

  一是通過各種 Web 技術實現與原生 App 相近的使用者體驗,即Web 應用漸進式接近原生 App

  二是由於在當時的背景下,一些瀏覽器暫時不支援,可以利用 PWA 相關技術,給支援 PWA 的瀏覽器使用者帶來更好的體驗

  另外,也許你聽過漸進增強(Progressive Enhancement)和優雅降級(Graceful Degradation)這兩個概念。

  漸進增強:針對低版本瀏覽器進行構建頁面,完成基本的功能,然後再針對高階瀏覽器進行效果、互動、追加功能以達到更好的體驗。

  優雅降級:構建站點的完整功能,然後針對瀏覽器測試和修復。比如一開始使用 CSS3 的特性構建了一個應用,然後逐步針對各大瀏覽器進行 hack 使其可以在低版本瀏覽器上正常瀏覽。

  PWA 本質上是 WEB 應用,所以,我覺得這種“漸進式”其實是一種漸進增強的理念。

PWA 的概念

中文官網解釋:採用所有正確組成要素的網站。

pwa

  PWA 是 Google 於 2016 年提出的概念,於 2017 年正式落地,於 2018 年迎來重大突破,全球頂級的瀏覽器廠商,Google、Microsoft、Apple 已經全數宣佈支援 PWA 技術

  縱觀現有 Web 應用與原生應用的對比差距,如離線快取、沉浸式體驗等等,可以通過已經實現的 Web 技術去彌補這些差距,最終達到與原生應用相近的使用者體驗效果。

  一個 PWA 應用首先是一個網頁, 可以通過 Web 技術編寫出一個網頁應用. 隨後新增上 App Manifest 實現新增至主螢幕, 通過 Service Worker 來實現離線快取和訊息推送等功能

  Web Application Manifest,即通過一個清單檔案向瀏覽器暴露 web 應用的後設資料,包括名稱、icon 的 URL 等,以備瀏覽器使用,比如在新增至主屏或推送通知時暴露給作業系統,從而增強 web 應用與作業系統的整合能力。

  我們原有的整個 Web 應用模型,都是構建在「使用者能上網」的前提之下的,所以一離線就只能玩小恐龍了。其實,對於「讓 web 應用離線執行」這件事,最早可以追溯到 2007 年的 Google Gears:為了讓自家的 Gmail、Youtube、Google Reader 等 web 應用可以在本地儲存資料與離線執行,Google 開發了一個瀏覽器擴充來增強 web 應用。Google Gears 支援 IE 6、Safari 3、Firefox 1.5 等瀏覽器;要知道,那一年 Chrome 都還沒出生呢。

Gears,前身為 Google Gears,是由 Google 提供的已停產的實用軟體,用於通過向 Web 瀏覽器新增離線儲存和其他附加功能來建立更強大的 Web 應用程式。Gears 是在沒有可比替代品的時候構思的,後來,Gears 被終止,取而代之的是最終流行 的標準化 HTML5 方法。在 Gears API 中,我們通過向 LocalServer 模組提交一個快取檔案清單來實現離線支援。

  Service Worker 是一個可程式設計的 Web Worker,它就像一個位於瀏覽器與網路之間的客戶端代理,可以攔截、處理、響應流經的 HTTP 請求;配合隨之引入 Cache Storage API,你可以自由管理 HTTP 請求檔案粒度的快取,這使得 Service Worker 可以從快取中向 web 應用提供資源,即使是在離線的環境下。

PWA 實現

sw_img

實現

  一個簡單的 PWA demo 很簡單,新建專案目錄,然後:

touch index.html
touch sw.js
npm install serve -g

  之後進行簡單的 html 和 sw.js 檔案的編寫,最後通過 manifest.json 實現新增到桌面功能,完整程式碼可以檢視這裡

// manifest.json
{
  "name": "Progressive Web App",
  "short_name": "PWA",
  "description": "Progressive Web App.",
  "icons": [
    {
      "src": "/icon.png",
      "sizes": "288x288", // 這裡需要格外注意圖片的尺寸,如果圖片有問題,除錯頁面Manifest裡會給你提示
      "type": "image/png"
    }
  ],
  "start_url": "/",
  "display": "standalone",
  "theme_color": "#B12A34",
  "background_color": "#B12A34"
}

  示例 demo:

pwa_demo

  通過對 manifest.json 進行相應配置,可以實現以下功能:

manifest

App Shell 模型

  另外,我覺得有必要介紹一下的是 App Shell 模型。

  App Shell 架構是構建 Progressive Web App 的一種方式,這種應用能可靠且即時地載入到您的使用者螢幕上,與本機應用相似。

  App“shell”是支援使用者介面所需的最小的 HTML、CSS 和 JavaScript,如果離線快取,可確保在使用者重複訪問時提供即時、可靠的良好效能。這意味著並不是每次使用者訪問時都要從網路載入 App Shell,只需要從網路中載入必要的內容。

  對於使用包含大量 JavaScript 的架構的單頁應用來說,App Shell 是一種常用方法。這種方法依賴漸進式快取 Shell(使用 Service Worker 執行緒)讓應用執行,接下來,為使用 JavaScript 的每個頁面載入動態內容。App Shell 非常適合用於在沒有網路的情況下將一些初始 HTML 快速載入到螢幕上。

appshell

從微博 Lite 看 PWA

  安裝 PWA:

weibo_install

  安裝後,PWA 應用就會出現在桌面/Chrome 應用裡面:

weibo_icon

  從下圖可以看出,點選桌面圖示開啟後,我們可以選擇解除安裝 PWA,圖示將會從桌面移除;同時,我們還可以發現,微博 Lite 除了快取圖片、JS、CSS 等靜態資源外,也會快取介面:

weibo_detail

  當我們將網路設定成離線時,重新整理頁面,依然可以繼續瀏覽頁面上上次載入過的資訊,提升使用者體驗:

weibo_offline

PWA 的優勢與劣勢

pwa_processon

  在這些存在的問題裡面,簡單介紹一下摩爾定律。

  個人認為,摩爾定律是晶片領域的 OKR。摩爾在 1965 年文章中指出,晶片中的電晶體和電阻器的數量每年會翻番,原因是工程師可以不斷縮小電晶體的體積。這就意味著,半導體的效能與容量將以指數級增長,並且這種增長趨勢將繼續延續下去。1975 年,摩爾又修正了摩爾定律,他認為,每隔 24 個月,電晶體的數量將翻番。

  電晶體數量翻倍帶來的好處可以總結為:更快,更小,更便宜。根據摩爾定律,晶片設計師的主要任務便是縮小電晶體的大小,然後讓晶片能夠容納越多的電晶體。電晶體的增加可以讓設計師為晶片新增更多的功能,比如 3D 顯示卡,從而節約成本。

  可以看出,摩爾定律是和我們書本上看到的公式、定理存在很大區別的,它更多的是一個經驗總結,是晶片領域自驅的 OKR

  如果說一開始人們埋怨手機記憶體和流量資費的限制,而不想安裝太多的 App,根據摩爾定律,現在的手機記憶體與硬體都在提升,運營商資費下調。這使得 PWA 最初得以出現的根基開始動搖。所以,PWA 現在國內面臨的處境即:使用者不知道,也不會用,開發者不見得支援,也不如小程式友好。

  儘管有上述的一些缺點,PWA 技術仍然有很多可以借鑑和使用的點:

  • Service Worker 技術實現離線快取,可以將一些不經常更改的靜態檔案放到快取中,提升使用者體驗。
  • Service Worker 實現訊息推送,使用瀏覽器推送功能,吸引使用者
  • 漸進式開發,儘管一些瀏覽器暫時不支援,可以利用上述技術給使用支援瀏覽器的使用者帶來更好的體驗
當然,在通知這一塊兒,拋開 PWA 不談,瀏覽器通知 API Notification也是一個不錯的選擇。

Javascript Workers

  我們知道,JavaScript 是圍繞單執行緒的概念設計的,缺乏實現像原生 App 那樣的多執行緒模型所需的功能,比如共享記憶體。

  瀏覽器使用單個執行緒(主執行緒)來執行網頁中的所有 JavaScript、執行渲染頁面和執行垃圾收集等任務。執行過多的 JavaScript 程式碼會阻塞主執行緒,延遲瀏覽器執行這些任務並導致糟糕的使用者體驗。

  在 Web 中可以通過使用 Workers 在後臺執行緒中執行指令碼來實現類似多執行緒的模式,允許它們執行任務而不干擾主執行緒。Workers 是執行在單獨執行緒上的整個 JavaScript 作用域,沒有任何共享記憶體。

  一般來說,Worker 可以讓指令碼在瀏覽器主執行緒之外的單獨的執行緒上執行。如果你想要在 HTML 文件中引用一個<script>標籤的典型的 JavaScript 檔案,它會執行在主執行緒上。如果主執行緒上有太多的計算,會拖慢網站的速度,造成互動卡頓和響應延遲。Web worker,Service worker 和 Worklet 都是讓腳步執行在單獨的執行緒上的。

workers

參考資料:Web workers vs Service workers vs Worklets

Web worker

  Web workers 是最常用的 worker 型別。它不像另外兩種,它們除了執行在主執行緒外的特性外,沒有一個特殊的應用場景。所以,Web worker 可以用於減少主執行緒上大量的執行緒活動。

web-worker

推薦閱讀:Workers overview

  一個很好的例子是前文提到的影像處理 Web 應用程式Squoosh,它使用 Web Worker 來進行影像處理任務,讓主執行緒可供使用者與應用程式進行不中斷的互動

  PROXX也使用了 Web worker 和 Service Worker 相關技術,具體可參考Proxx: Building Fast Web Applications

  Web Worker 有以下幾個使用注意點:

  • 同源限制:分配給 Worker 執行緒執行的指令碼檔案,必須與主執行緒的指令碼檔案同源。
  • DOM 限制:Worker 執行緒所在的全域性物件,與主執行緒不一樣,無法讀取主執行緒所在網頁的 DOM 物件,也無法使用 document、window、parent 這些物件。但是,Worker 執行緒可以使用 navigator 物件和 location 物件。
  • 通訊聯絡:Worker 執行緒和主執行緒不在同一個上下文環境,它們不能直接通訊,必須通過訊息(postMessage)完成。
  • 指令碼限制:Worker 執行緒不能執行 alert()方法和 confirm()方法,但可以使用 XMLHttpRequest 物件發出 AJAX 請求。
  • 檔案限制:Worker 執行緒無法讀取本地檔案,即不能開啟本機的檔案系統(file://),它所載入的指令碼,必須來自網路。
更多使用細節可參考阮一峰的Web Worker 使用教程

Service worker

  Service workers 主要是提供詳細的瀏覽器和網路/快取間的代理服務,如下圖所以:

service-worker

  2014 年,W3C(全球資訊網聯盟)公佈了 Service Worker 的相關草案,但真正在生產環境被 Chrome 支援是在 2015 年,比微信小程式要早兩年。

  下圖展示了 Service workers 的生命週期:

sw-lifecycle

  而下面這張圖則幾乎涵蓋了 Service workers 所有最重要的知識點

原圖來自 GitHub:service-workers-101

sw-lifecycle

HTTP 快取與 Service Worker 快取

  可能你會好奇,用 Service Workers 來做快取?HTTP 快取它不香嗎?我們可以簡單看看這兩者的區別:

  • HTTP 快取中,Web 伺服器可以使用 Expires 首部來通知 Web 客戶端,它可以使用資源的當前副本,直到指定的“過期時間”。反過來,瀏覽器可以快取此資源,並且只有在有效期滿後才會再次檢查新版本。
    使用 HTTP 快取意味著你要依賴伺服器來告訴你何時快取資源和何時過期(當然,HTTP 快取控制還包括 cache-control,last-modified,etag 等欄位)。
  • Service Workers 的強大在於它們攔截 HTTP 請求的能力,接受任何傳入的 HTTP 請求,並決定想要如何響應。在你的 Service Worker 中,可以編寫邏輯來決定想要快取的資源,以及需要滿足什麼條件和資源需要快取多久。一切盡歸你掌控!(所以,出於安全考慮,Service Workers 要求只能由 Https 承載)

注意事項

  • Service worker 執行在 worker 上下文(self) --> 不能訪問 DOM(這裡其實和 Web Worker 是一樣的);
  • 它設計為完全非同步,同步 API(如 XHR 和 localStorage)不能在 service worker 中使用;
  • 出於安全考量,Service workers 只能由 HTTPS 承載;
  • 某些瀏覽器的使用者隱私模式,Service Worker 不可用;
  • 其生命週期與頁面無關(關聯頁面未關閉時,它也可以退出,沒有關聯頁面時,它也可以啟動)。

離線快取

  由於 Service Worker 的出現,我們不再嘗試離線解決問題,而是讓開發人員自己動手解決快取問題。通過它可以控制快取以及如何處理請求。這意味著您可以建立自己的模式。

  快取的模式有很多中,在離線指南中,全面介紹了各種快取的模式,在實踐中,你可能需要根據 URL 和上下文同時使用多種模式。

  當然,無論您做了多少快取, Service Worker 程式都不會使用快取,除非你告訴它何時以及如何使用。下圖展示的是快取優先的示意圖:

cache_prior

  其他一些快取模式簡單梳理如下:

cache

除錯

service_debug

相容性

can_i_use_sw

can_i_use_manifest

  可以看出,相容性問題最大的其實還是在 manifest.json 的支援上。

Worklet

  Worklet 是一個非常輕量級、高度具體的 worker。它。它們使我們作為開發人員能夠連線到瀏覽器渲染過程的各個部分(鉤子),讓開發人員可以訪問渲染管道的底層部分。

  當一個 web 頁面正在被渲染,瀏覽器經過很多步驟。在這裡我們需要關注的有四步:Style,Layout,Paint 和 Composite。

  在展示網頁時,瀏覽器會執行多個步驟。在這裡我們主要關注四個步驟:Style,Layout,Paint 和 Composite(合成)。

frame-full

  Paint 是瀏覽器將樣式應用於每個元素的地方。與此渲染階段掛鉤的 Worklet 是 Paint Worklet。Paint Worklet 允許我們建立自定義圖片,這個圖片可以應用任何 CSS,比如 background-image 屬性的值。

  要建立一個 Worklet,就像所有 Worker 一樣,我們在我們的主 javascript 檔案中註冊它,引用專用的 Worklet 檔案。

/* main.js */
CSS.paintWorklet.addModule('myWorklet.js');

  在我們的 Worklet 檔案中,我們可以建立自定義影像。該 paint 方法的工作方式與 Canvas API 非常相似。這是一個簡單的黑白漸變示例。

/* myWorklet.js */

registerPaint(
  'myGradient',
  class {
    paint(ctx, size, properties) {
      var gradient = ctx.createLinearGradient(0, 0, 0, size.height / 3);
      gradient.addColorStop(0, 'black');
      gradient.addColorStop(0.7, 'rgb(210, 210, 210)');
      gradient.addColorStop(0.8, 'rgb(230, 230, 230)');
      gradient.addColorStop(1, 'white');

      ctx.fillStyle = gradient;
      ctx.fillRect(0, 0, size.width, size.height / 3);
    }
  }
);

  最後,我們可以在 CSS 中使用這個新的 Worklet,我們建立的自定義影像將像任何其他背景影像一樣應用。

div {
  background-image: paint(myGradient);
}

  除了 Paint Worklet,還有其他的 worklet 可以連線到渲染過程的其他階段。Animation Worklet 連線到 Composite 階段,而 Layout Worklet 連線到 Layout 階段。

總結

  Web worker,Service worker 和 worklet 都是將指令碼執行在瀏覽器主執行緒之外單獨的執行緒中,它們之間的區別是它們所應用的場景和他們的特性。

  • Worklet 是瀏覽器渲染流中的鉤子,可以讓我們有瀏覽器渲染執行緒中底層的許可權,比如樣式和佈局;
  • Service worker 是瀏覽器和網路間的代理。通過攔截文件中發出的請求,service worker 可以直接請求快取中的資料,達到離線執行的目的。
  • Web worker 的通常目的是讓我們減輕主執行緒中的密集處理工作。

PWA 發展與現狀

PWA in China

  看看 Google 官方宣傳較多的 PWA 案例就會發現,FlipKart、Housing.com 來自印度;Lyft、華盛頓郵報來自北美;唯一來自中國的 AliExpress 主要開展的則是海外業務。

由於中國的特殊性,PWA 的前景在一定程度上比較悲觀:

  • 國內較重視 iOS,而 iOS 目前還不支援 PWA。
  • 國內的 Android 實為「安卓」,不自帶 Chrome 是一,可能還會有其他相容問題。
  • 國內廠商可能並不會像三星那樣對推動自家瀏覽器支援 PWA 那麼感興趣。
  • 依賴 GCM 推送的通知不可用,Web Push Protocol 還沒有國內的推送服務實現。
  • 國內 webview 環境較為複雜(比如微信),黑科技比較多。

  反觀印度,由於 Google 服務健全、標配 Chrome 的 Android 手機市佔率非常高,PWA 的使用者達到率簡直直逼 100%,也難免獲得無數好評與支援了。

參考資料: 下一代 Web 應用模型 —— Progressive Web App | 小程式的老祖宗 PWA 為什麼沒有火起來?

百度

  在 2017 年 7 月 5 日“百度 AI 開發者大會”(Baidu Create2017)——Web 生態分論壇上,百度開發者介紹了百度 Lavas 解決方案,幫助開發者快速搭建 PWA 應用。

  lavas 不是一個框架,而是一個基於 vue 的 PWA 解決方案,通過 lavas 匯出的模板幫助開發者解決了接入 PWA 過程中遇到的問題:

  • Service Worker 生成
  • Service Worker 更新,以及 sw 更新後的操作
  • App Skeleton,頁面渲染完成之前的頁面框架
  • 頁面切換前進後退過渡動畫
  • App Shell,整合了 vuetify 元件庫
  • 主題切換
  • vue 的圖示解決方案...

  而現在 lavas 官網已經無法訪問,這在很大程度上可以反應 PWA 在國內業務的一個現狀。

微軟

  Microsoft 依然在維護著相關文件:Get started with Progressive Web Apps,時間顯示,最近更新時 2022 年 3 月 1。

Microsoft

總結:App、小程式、快應用與 App Clips

App

高清大圖可點選這裡檢視。

推薦參考資料

  本文首發於個人部落格,歡迎指正和 star

相關文章