pwa

https://juejin.im/post/5a9e8ad5f265da23a40456d4?utm_source=gold_browser_extension

什么是 PWA

編者按
本文作者:吳昀珠(機智哥)
個人主頁:https://github.com/cleverboy32

什么是 PWA

先說一下全名,progressive web app: 漸進式網(wǎng)頁應用。這是谷歌推出的,我是這樣理解的:

  • 我們一般寫 web 應用,在 pc 上是沒有緩存的,打開頁面的時去請求數(shù)據(jù)。

  • 第二個也沒有像 app 一樣的小圖標放在桌面,一點開就進入了應用,而是通過打開瀏覽器輸入網(wǎng)址,

  • 第三個就是,不能像 app 一樣給用戶推送消息,像微博會跟你推送說有誰評論了你的微博之類的功能。

而谷歌推出的 pwa,就是具有這些了這些特點, 使我們的 web 應用,能夠像一款 app 一樣使用。并且對比與 app, 它不用復雜的安裝,也不用下載更新包,刷新頁面就可以了(注意到緩存的處理)。

那么這些功能分別是怎么實現(xiàn)的呢?

關于緩存

其實這個就是 我們平時做的 Session 啊、localStorage、CacheStorage 之類的。

這里用的就是 cacheStorage 緩存,它提供了一個ServiceWorker類型的工作者或window范圍可以訪問的所有命名緩存的主目錄, 并維護字符串的映射名稱到相應的 Cache 對象。 主要方法包括:

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳失敗...(image-c91e4c-1520342971098)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

有了這些方法你可以對你的緩存進行操作。目前還在草案狀態(tài),僅火狐和谷歌瀏覽器支持此特性。

PWA是通過 ServiceWorker 訪問 cache ,所以需要注冊 ServiceWorker 工作者。在之前別忘記判斷瀏覽器是否支持。

if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register(sw.js) // 注冊sw.js 文件中變成的服務對象,返回注冊成功的對象
    .then(function(swReg){
          swRegistration = swReg;
     }).catch(function(error) {
          console.error('Service Worker Error', error);
     });
}

這個 Service Worker 服務工作者就厲害了,它相當于瀏覽器和網(wǎng)絡之間的代理服務器,可以攔截網(wǎng)絡請求,做一些你可能需要的處理(請求資源從緩存中獲取等)。

  • 它能夠創(chuàng)建有效的離線體驗,攔截網(wǎng)絡請求,并根據(jù)網(wǎng)絡是否可用判斷是否使用緩存數(shù)據(jù)或者更新緩存數(shù)據(jù)。

  • 它們還允許訪問推送的通知和后臺的API。

關于 sw.js 中具體的緩存的代碼:

創(chuàng)建需要緩存的文件

'use strict'
let cacheName = 'pwa-demo-assets'; // 緩存名字
let imgCacheName = 'pwa-img';
let filesToCache;
filesToCache = [ // 所需緩存的文件
    '/',
    '/index.html',
    '/scripts/app.js',
    '/assets/imgs/48.png',
    '/assets/imgs/96.png',
    '/assets/imgs/192.png',
    '/dist/js/app.js',
    '/manifest.json'
];

self.addEventListener('install', function(e) {
    e.waitUntil(
        // 安裝服務者時,對需要緩存的文件進行緩存
        caches.open(cacheName).then(function(cache) {
            return cache.addAll(filesToCache);
        })
    );
});

self.addEventListener('fetch', (e) => {
    // 判斷地址是不是需要實時去請求,是就繼續(xù)發(fā)送請求
    if (e.request.url.indexOf('/api/400/200') > -1) {
        e.respondWith(
            caches.open(imgCacheName).then(function(cache){
                 return fetch(e.request).then(function (response){
                    cache.put(e.request.url, response.clone()); // 每請求一次緩存更新一次新加載的圖片
                    return response;
                });
            })
        );
    } else {
        e.respondWith(
            // 匹配到緩存資源,就從緩存中返回數(shù)據(jù)
            caches.match(e.request).then(function (response) {
                return response || fetch(e.request);
            })
        );
    }

});

這里進而就引入到 pwa 的推送通知功能。這都是通過 ServiceWorker 去實現(xiàn)的。

基本原理是,你的客戶端要和推送服務進行綁定,會生成一個綁定后的推送服務 API 接口,服務端調用此接口,發(fā)送消息。同時,瀏覽器也要支持推送功能,在注冊 sw 時, 加上推送功能的判斷。

if ('serviceWorker' in navigator && 'PushManager' in window) {
    navigator.serviceWorker.register(sw.js)
    .then(function(swReg) {
        swRegistration = swReg;
    }).catch(function(error) {
        console.error('Service Worker Error', error);
        });
 } else {
     console.warn('Push messaging is not supported');
 }

PushManager 注冊好之后, 那么要做的就是瀏覽器和服務器的綁定了。

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳失敗...(image-1f78f1-1520342971097)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

此圖是用戶訂閱某個應用程序的推送服務。 客戶端傳入應用程序服務器公鑰,向將生成端點的 webpush 服務器( 這是谷歌自己實現(xiàn)的一個推送功能的服務器)發(fā)出網(wǎng)絡請求,將生成的端點(一個推送服務)與應用程序公鑰關聯(lián),并將端點返回給應用程序。瀏覽器會將此端點添加到 PushSubscription,通過 promise異步成功時,可以將它的信息保存到你的數(shù)據(jù)庫。

<figure style="display: block; margin: 22px auto; text-align: center;">[圖片上傳失敗...(image-a575a0-1520342971097)]

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

</figure>

服務器發(fā)送推送的時候,請求相關接口,驗證成功后推送服務會發(fā)消息給客戶端。

最后關于桌面小圖標

這個可以說是非常簡單了,就是一個 manifest.json 配置文件,然后在頁面引入此文件就好了

<!-- 加載清單 -->
<link rel="manifest" href="./manifest.json">

關于清單內容這里簡單介紹一下:

{
    "short_name": "pwa",
    "name": "pwa - demo", // 應用名稱
    "icons": [ // 應用顯示圖標,根據(jù)容器大小適配
        {
            "src": "assets/imgs/48.png",
            "type": "image/png",
            "sizes": "48x48"
        },
        {
            "src": "assets/imgs/96.png",
            "type": "image/png",
            "sizes": "96x96"
        },
        {
            "src": "assets/imgs/192.png",
            "type": "image/png",
            "sizes": "192x192"
        }
    ],
    "background_color": "#2196F3", // 剛打開頁面時的背景
    "theme_color": "#2196F3", // 主題顏色
    "display": "standalone", //獨立顯示
    "start_url": "index.html?launcher=true" // 啟動的頁面
}

好了, 如果感興趣趕快上手吧。 可以查看谷歌官方教程。

這里說一下坑的點, PWA應用需要在本地localhost:8080 上運行或者 https 協(xié)議下, 要保證你的頁面是安全頁面。

添加桌面時,確保你的谷歌瀏覽器可以顯示彈出通知。

如果你要自己實現(xiàn)推送,自己服務器要有公鑰和私鑰的獲取, 這里可以通過 https://web-push-codelab.glitch.me 獲取, 用 chrome 的 webpush 推送。

這里也可以看一下我的 GitHub 項項目 ,官方也有很多例子。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容