Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PWA调研 #21

Open
UNDERCOVERj opened this issue Jul 5, 2020 · 0 comments
Open

PWA调研 #21

UNDERCOVERj opened this issue Jul 5, 2020 · 0 comments

Comments

@UNDERCOVERj
Copy link
Owner

UNDERCOVERj commented Jul 5, 2020

前言

之前看到有使用ant-design-pro的网站,在服务端更新后,前端会提示刷新页面。但是在调研后发现service-worker.js的更新,只会在重刷页面时检测到,并不会在已经开的tab里被检测到。所以之前看到的可能的情况可能是:有两个tab,一个tab刷新,另外一个tab就能检测service-worker.js。这样的话也不好用。

概述

PWA(Progressive Web App)渐进式网页应用,所谓渐进式,意思就是主张很少,你不用遵守一系列的约束条件。提升 Web App 体验,能给用户原生应用的体验

特性

  1. 跨平台,可安装,独立窗口,沉浸式体验
  2. 消息推送
  3. 缓存
  4. 离线可用

实践

从四个特性来详细讲讲实践效果。

app安装

条件

  1. 在header头里,提供manifest
<link rel="manifest" href="/assets/manifest.json">
  1. 只https可用

  2. manifest.json里提供icon,size > 144

  3. 注册service worker

效果

小结

可以像app一样,安装在桌面,并提供沉浸式的体验,但是感觉和safari浏览器打开有点一样,与safari的区别就是最顶上的mac工具栏没有了。

消息推送

在service-worker.js里监听push事件,并使用self.registration.showNotification(title, options)。需要依赖Notification api。

使用

服务端使用web-push

  1. 在service-worker.js里activate时,向node发送注册subscribe,node把subscription对象存下来.
  2. 在service-worker.js里监听push事件
  3. node调用 webpush.sendNotification(subscription, dataToSend)

效果

略,就是桌面上安装个app一样,

代码示例

  1. 初始化

serivce-worker.js

self.addEventListener('activate', () => {
    self.registration.pushManager.subscribe().then((subscription) => {
        fetch(SERVER_URL, {
            method: "POST",
            headers: {
              'Content-Type': 'application/json',
            },
            body: JSON.stringify(subscription)
        })
    })
})

node


// 初始化subscription
app.post('/save-subscription', async (req, res) => {
    const subscription = req.body;
    await saveToDatabase(subscription);
    res.json({ message: 'success' });
});

// 发送消息
app.get('/send-notification', (req, res) => {
  const subscription = db.subscription;
  const message = 'Hello World';
  webpush.sendNotification(subscription, message);
  res.json({ message: 'message sent' });
})
  1. Push listener
self.addEventListener('push', function(event) {
    const title = 'Push service';
    const options = {
      body: 'Yay it works.',
      icon: 'images/icon.png',
      badge: 'images/badge.png'
    };
  
    event.waitUntil(self.registration.showNotification(title, options));
});
  1. Notification api
document.addEventListener('DOMContentLoaded', function () {
    if (!Notification) {
        console.log('Notification not support')
        return;
    }
    if (Notification.permission !== 'granted') {
        Notification.requestPermission();
    }
});


function notifyMe() {
    if (Notification.permission !== 'granted') {
        Notification.requestPermission();
    } else {
        const notification = new Notification('Notification opened', {
            icon: 'xxx.png',
            body: 'hello',
        });
        notification.onclick = function () {
            window.open('xxx');
        };
    }
}

小结

  1. 单实例做broadcast,可以将缓存里的subscription遍历,并发消息。但是分布式集群很难做,不过也需要像websocket一样,再依赖redis、kafka

缓存

利用service worker来做静态资源的缓存,根据匹配url、正则,第一次获取将资源存在Cache Storage里,如果service-worker.js有更新,会重新获取最新的资源,并再次cache。支持离线缓存

tips:跨域缓存需要 workbox-cacheable-response 插件

缓存策略

  1. CacheFirst:缓存、回退到网络。适用于离线优先方式构建,对缓存中的资源提供缓存,对未在缓存中的资源提供网络请求并缓存下来
  2. CacheOnly:仅缓存,适用于静态资源
  3. NetworkFirst: 网络、回退到缓存。为在线用户提供最新内容,但离线用户会获得较旧的缓存版本。适用于频繁更新的资源
  4. NetworkOnly:仅网络请求,适用于没有相应离线资源的对象
  5. StaleWhileRevalidate:缓存、网络同时进行,适用于网络比硬盘读取更快。会造成流量浪费

缓存优先级

  1. Service Worker,可自行操作缓存策略
  2. Memory Cache
  3. Disk Cache(http缓存),server下发http头控制。响应内容的引用存入Memory Cahce
  4. 网络请求

效果

image

代码示例

workbox.routing.registerRoute(
    /.*\.(?:|png|gif|jpg|jpeg|svg|mp4|js|css|image)$/,
    new workbox.strategies.CacheFirst({
        plugins: [
            new workbox.cacheableResponse.CacheableResponsePlugin({
                statuses: [0, 200]
            })
        ]
    })
);

小结

  1. service worker缓存应用场景:离线缓存。但感觉静态资源有cdn的支持,走memory cache、disk cache足够了。
  2. HTTP缓存空间有限,容易被冲掉。多一层缓存,命中的概率更高了。

离线可用

监听fetch事件,如果是路由请求,则返回离线html

self.addEventListener('fetch', (evt) => {
  if (evt.request.mode !== 'navigate') {
    return;
  }
  evt.respondWith(
      fetch(evt.request)
          .catch(() => {
            return caches.open(CACHE_NAME)
                .then((cache) => {
                  return cache.match('offline.html');
                });
          })
  );
});

小结

可以用,但没啥必要

整体总结

  1. web app安装可取,可提升体验。其它不是很需要。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant