1. 程式人生 > 其它 >PWA漸進式web應用

PWA漸進式web應用

PWA核心技術,web app manifest,service worker,promise/async/await,fatch api,Cache storage,常見快取策略,notification

PWA(Progressive Web App)是一種理念,使用多種技術來增強web app的功能,可以讓網站的體驗變得更好,能夠模擬一些原生功能,比如通知推送。在移動端利用標準化框架,讓網頁應用呈現和原生應用相似的體驗。

PWA核心技術

  • web app manifest
  • service worker
  • promise/async/await
  • fatch api
  • Cache storage
  • 常見快取策略
  • notification

PWA四個核心內容

  1. manifest.json
  2. serviceWork
  3. cacheStrorage
  4. notification

1、manifest

  • pwa技術集合的一部分
  • 讓網站安裝到裝置主螢幕上,不需要使用者在商城下載
  • 在json檔案中提供有關應用的資訊
  • 啟動頁面避免生硬過度
  • 隱藏瀏覽器相關的UI 比如位址列等

注意點

  1. manifest.json 配置
  2. index.html 中引入manifest.json
  3. 需要https或者http://localhost下訪問

常見配置

  • name: 專案名稱
  • short_name:短名稱,用於主螢幕顯示
  • start_url:裝置應用載入的url 可以使絕對或者相對路徑
  • icons : 應用圖示144X144
  • background_color:啟動動畫背景色
  • theme_color:應用程式主題背景色
  • dispay:app顯示模式 fullcreen全屏 standalone minimal-ui
{
    "name":"電影App",
    "short_name":"app",
    "start_url":"/index.html",
    "icon":[{
        "src":"icons/icon_fro.png",
        "sizes":"144x144",
        "type":"image/png"
    }],
    "background_color":"skyblue",
    "theme_color":"yellow",
    "display":"standalone"
}

2、service worker

  • 標準的PWA包括3個部分
    https或http://localhost
    manifest.json
    service work
  • 做離線快取

web work使用

  • 建立web worker var worker = new Worker('work.js')
  • 在web work 中進行復雜計算
  • web work計算結束 通過self.postMessage(msg)給主執行緒發訊息
  • 主執行緒通過 worker.onMessage = function(msg) 監聽訊息
  • 主執行緒可以用同樣的方式給web worker進行通訊

service worker

  • web work 臨時的,每次事情不能持久存下來。
  • servive work 類似於代理伺服器,存在快取裡
  1. 一旦install ,永久存在,除非被手動unregister
  2. 用到的時候喚醒,不用自動休眠
  3. 必須https環境下工作
  4. 非同步實現,內不通過Promise實現
  5. 可程式設計連結代理請求和返回,快取檔案,快取的檔案可以被網頁程序取到(包括網路離線狀態)

service worker使用步驟

  • window.onload 中註冊service worker ,放在與其他資源競爭
  • navigator物件中內建了serviceWorker屬性
  • service worker在老版本不支援,需要進行瀏覽器相容 if('serviceWorker' in navigator){}
  • 註冊service worker navigator.serviceWorker.register('./sw.js')返回一個promise物件

service worker生命週期事件

  • install: 註冊成功觸發,使用者快取資源
  • activate:啟用時觸發,刪除舊的資源
  • fetch 傳送請求時觸發,操作快取讀取網路資源

fetch Api

config常見引數
body
headers
methods
index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 引入清單檔案 -->
    <link rel="manifest" href="manifest.json">
</head>

<body>
    <h1>hello word</h1>
    <!-- web worker -->
    <script>
        const worker = new Worker('worker.js')
        worker.addEventListener('message', e => {
            console.log(e.data)
        })
    </script>
    <!-- service worker -->
    <script>
        // 1.需要網頁載入完成註冊
        window.onload = () => {
            // 2.能力監測
            if ('serviceWorker' in navigator) {
                navigator.serviceWorker.register('./sw.js').then(res => {
                    console.log(res)
                })
            }
        }
    </script>
</body>

</html>

webwork.js

// 獨立的程序,不能做dom操作
let total = 0 
for(var i=0;i<1000000;i++){total+=i}
// 發訊息給主執行緒,把結果給他
self.postMessage({total:total})

sw.js (serviceWorker)

console.log('service註冊')
self.addEventListener('install', e => {
    console.log(e)
    /*  
     跳過等待,直接到activite狀態 是一個promise
      self.skipWaiting() 
     */

    // 等待skipWaiting結束,activite狀態 是一個promise
    e.waitUntil(self.skipWaiting())
})
self.addEventListener('activate', e => {
    //   表示service work啟用後,利可獲取控制權
    e.waitUntil(self.ClientRectList.claim())
})
self.addEventListener('fatch', e => {
    console.log(e)
})

3、cacheStorage基本使用

  • cache物件的儲存,配合service work使用

api類似於資料庫操作

  • caches.open(name).then(function(){}):用於開啟快取
  • caches.keys(資料庫名):返回一個promise
  • caches.delete(資料庫)

cache常用方法

cache介面快取的request/response物件提供儲存機制

  • cache.put(req,res)把請求當成key,把相應儲存起來
  • cache.add(url) 根據url請求,吧響應結果儲存起來
  • cache.addAll(urls)抓取url陣列,把結果存起來
  • cache.match(req)獲取req對應的response
    index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 引入清單檔案 -->
    <link rel="manifest" href="manifest.json">
</head>
<body>
    <h1>hello word</h1>
    <script>
        window.addEventListener('load', async()=>{
            if('serviceWorker' in navigator){
                try {
                    const registration=await navigator.serviceWorker.register('./sw.js')
                    console.log('成功')
                } catch (error) {
                    console.log('失敗')
                }
            }
        })
    </script>
</body>
</html>

sw.js

// 註冊serviceWorker時間
const CACHENAME = 'chache_v1'
// 快取內容
self.addEventListener('install', async (e) => {

    const cache = await caches.open(CACHENAME)
    await cache.addAll([
        '/',
        '/icons/icon_fro.png',
        'manifest.js'
    ])
    e.waitUntil(self.skipWaiting())
})
// 清除就得快取
self.addEventListener('activate', async e => {
    const keys = await caches.keys()
    keys.forEach(key => {
        if (key == CACHENAME) {
            caches.delete(key)
        }
    })
    e.waitUntil(self.clients.claim())
})
// 請求時間觸發
// 能請求:請求
// 不能請求:讀取cachesStorage
self.addEventListener('fetch', e => { 
    // 請求物件
const req=e.request
// 給瀏覽器響應
e.respondWith(networkFirst(req))

})
// 網路有限
async function networkFirst(req){
    try {
        const fresh=await fetch(req)
        return fresh
    } catch (error) {
        // 去快取讀取
        const cache=await caches.open(CACHENAME)
        const cached=await cache.match(req)
        return cached
    }
}

4、notiication 通知

  • 配置桌面通知的
  • Notification.permisin 可以獲得使用者的授權情況
  1. default:未授權
  2. denied:拒絕
  3. granted:授權
  • Notification.requestPermission() 請求使用者授權
  • new Notification(title,{body:''}) 給個通知

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- 引入清單檔案 -->
    <link rel="manifest" href="manifest.json">
</head>
<body>
    <h1>hello word</h1>
    <script>
        window.addEventListener('load', async()=>{
            if('serviceWorker' in navigator){
                try {
                    const registration=await navigator.serviceWorker.register('./sw.js')
                    console.log('成功')
                } catch (error) {
                    console.log('失敗')
                }
            }
        })
        // 判斷是否聯網
        if(Notification.permission=='default'){
            // 請求提示許可權
            Notification.requestPermission()
        }
        if(!navigator.onLine){
            new Notification('提示',{body:'當前沒有網'})
        }
        window.addEventListener('online',e=>{
            new Notification('提示',{body:'又忘了,請重新整理訪問最新資料'})
   
        })
    </script>
</body>
</html>

靜態資源快取優先,動態資料請求有限