资讯专栏INFORMATION COLUMN

pwa 实战总结

xioqua / 477人阅读

摘要:现在表示公开支持。一旦安装完成,如果注册的没有变化,则显示为已激活的生命周期结束。一旦安装这步完成,便会激活,并控制在其范围内的一切。目前还在草案状态,仅火狐和谷歌浏览器支持此特性。

PWA初探 什么是PWA

PWA(Progressive Web Apps):渐进式 Web app

PWA 旨在增强 Web 体验,能让用户在访问一个web的时候感觉在使用app一样。

PWA可以看作是一系列技术的结合体,它通过Manifist解决了首屏白屏、沉浸式的问题,更可以通过配置Manifist将web加到桌面上,使其像在访问原生app一样。并且,通过Service Worker解决了网络加载问题,可以使用户在离线的环境下也可以访问。并且service worker强大的网络请求拦截可以帮助用户更好的原生APP体验。

服务工作线程受 Firefox 和 Opera 支持。
Microsoft Edge 现在表示公开支持。
可以在 Jake Archibald 的 is Serviceworker ready 网站上查看所有浏览器的支持情况。

service worker的作用

主要有:
1 网络代理,转发请求,伪造响应;
2 离线缓存;
3 消息推送;
4 后台消息传递

Service Workers: PWA 的关键

Service Worker 是 Chrome 团队提出的Web API,主要用于做持久的离线缓存。

Service Worker这个概念可能比较难懂,它其实是在后台启动的一条服务worker 线程。

它不可以访问页面上的DOM元素,没有页面上的API,但是可以拦截所有页面上的网络请求,包括页面导航,请求资源,Ajax请求。

配合Cache Storage API,可以对页面发送的请求进行管理,这就是为什么Service Worker能让站点离线的原因。

在将来,基于它可以实现消息推送,静默更新以及地理围栏等服务,但是目前它首先要具备的功能是: 拦截和处理网络请求,包括可编程的响应缓存管理。

Service Workers 可以让你全权控制网站发起的每一个请求,这为许多不同的使用场景开辟了可能性。

Service Worker 运行在 worker 上下文中,这意味着它无法访问 DOM,它与应用的主要 JavaScript 运行在不同的线程上,所以它不会被阻塞。它们被设计成是完全异步的,因此你无法使用诸如同步 XHR 和 localStorage 之类的功能。

Service Worker 的几个特征

只能使用 HTTPS( 避免出现中间人攻击的情况)

运行在它自己的全局脚本上下文中

不绑定到具体的网页

无法修改网页中的元素,因为它无法访问 DOM

Service Worker 生命周期

https://developers.google.com...

Installing:发生在SW注册后,调用install事件进行静态资源的缓存

Installed:SW的完成安装,并且等待其他的Service Worker被关闭

Activating:在这个状态下没有被其他的 Service Worker 控制的客户端,允许当前的 worker 完成安装,并且清除了其他的 worker 以及关联缓存的旧缓存资源,等待新的 Service Worker 线程被激活。

Activated:一旦安装完成,如果注册的js没有变化,则显示为已激活

Redundant:Service Worker的生命周期结束。

可以看到生命周期分为这么几个状态: 安装中, 安装后, 激活中, 激活后, 废弃

这里特别说明一下,进入废弃 (redundant) 状态的原因可能为这几种:

安装 (install) 失败

激活 (activating) 失败

新版本的 Service Worker 替换了它并成为激活状态

1.当用户首次导航至 URL 时,服务器会返回响应的网页。
2.当你调用 register() 函数时, Service Worker 开始下载。在注册过程中,浏览器会下载、解析并执行 Service Worker 。如果在此步骤中出现任何错误,register() 返回的 promise 都会执行 reject 操作,并且 Service Worker 会被废弃。
3.一旦 Service Worker 成功执行了,install 事件就会激活。
4.一旦安装这步完成,Service Worker 便会激活, 并控制在其范围内的一切。如果生命周期中的所有事件都成功了,Service Worker 便已准备就绪,随时可以使用了!

需要注意的是,当第一次加载页面时,Service Worker 还没有激活,所以它不会处理任何请求。只有当它安装和激活后,才能控制在其范围内的一切。这意味着,只有你刷新页面或者导航到另一个页面,Service Worker 内的逻辑才会启动。

需要注意的是:首次注册 Service Worker 的页面将不会被控制,直到该页面再次被加载。

一旦 Service Worker 处于控制之下,它将处于以下状态之一:

它将处理当页面发出网络请求或消息时发生的 fetch 和 message 事件。

它将被终止以节省内存

生命周期的具体细节:

https://developers.google.com...

PWA 极简入门
PWA.zip14.70 KB已存到云盘下载

yarn && yarn start

运行起来:

注册服务工作线程

if ("serviceWorker" in navigator) {
  window.addEventListener("load", function() {
    navigator.serviceWorker.register("/sw.js")
      .then(function(registration) {
      // Registration was successful
      console.log("ServiceWorker registration successful with scope: ",  registration.scope);
    }).catch(function(err) {
      // registration failed :(
      console.log("ServiceWorker registration failed: ", err);
    });
  });
}

我们首先检查浏览器实际上是否支持 Service Workers 。如果支持,则在页面加载后注册位于
/sw.js
的服务工作线程。

每次页面加载无误时,即可调用 register()。

浏览器将会判断服务工作线程是否已注册并做出相应的处理。

register()方法的一个重要细节是 Service Worker 文件的位置。

在上面的例子中,可以看到 Service Worker 文件位于域的根目录。这意味着 Service Worker 的范围将是整个网站。换句话说,服务工作线程将接收此网域上所有事项的 fetch 事件。

如果我们在 /example/sw.js 处注册服务工作线程文件,则服务工作线程将只能看到网址以 /example/
开头(即 /example/page1/ , /example/page2/ )的页面的 fetch 事件。

安装服务工作线程

基础示例:

self.addEventListener("install", function(event) {
  // Perform install steps
});

在 install 回调的内部,我们需要执行以下步骤:
1.打开缓存。
2.缓存文件。
3.确认所有需要的资产是否缓存。

var cacheStorageKey = "minimal-pwa-8";

//  self 为当前 scope 内的上下文 
self.addEventListener("install", function(e) {
  console.log("Cache event!")
  // waitUntil用于在安装成功之前做一些预装逻辑
  // 安装内容建议轻量级,避免安装失败
  e.waitUntil(
    // 使用 cache API 打开指定的 cache 文件
    caches.open(cacheStorageKey).then(function(cache) {
      console.log("Adding to Cache:", cacheList)
      // 添加要缓存的文件
      // 缓存文件全部安装成功后,installing会变成installed,安装失败进入redundant状态
      return cache.addAll(cacheList)
    }).then(function() {
      // 跳过waiting,直接进入active
      console.log("Skip waiting!")
      return self.skipWaiting()
    })
  )
});

在这里您可以看到,我们以所需的缓存名称调用
caches.open()
,之后再调用
cache.addAll()
并传入文件数组。 这是一个 promise 链。

event.waitUntil()
方法带有 promise 参数并使用它来判断安装所花费的时间以及安装是否成功。

激活

安装成功后,会进入激活状态,此时触发active事件,通过active事件可以做一些预处理: 比如对旧版本的更新,或对无用缓存的清理.

self.addEventListener("activate", function(e) {
  console.log("Activate event")
  e.waitUntil(
    Promise.all(
      caches.keys().then(cacheNames => {
        return cacheNames.map(name => {
          if (name !== cacheStorageKey) {
            return caches.delete(name)
          }
        })
      })
    ).then(() => {
      console.log("Clients claims.")
      // 通过clients.claim方法,更新客户端上的server worker
      return self.clients.claim()
    })
  )
})
关于缓存

这里用的就是 cacheStorage 缓存,它提供了一个ServiceWorker类型的工作者或window范围可以访问的所有命名缓存的主目录, 并维护字符串的映射名称到相应的 Cache 对象。

主要方法包括:

有了这些方法你可以对你的缓存进行操作。目前还在草案状态,仅火狐和谷歌浏览器支持此特性。

http 缓存 / Manifest / Service Worker 三种 cache 的关系

三种缓存都使用时, 会以service worker 优先, 因为sw 把请求拦截了, 优先做处理,如果缓存库里有, 就直接返回, 没有就走正常请求。

然后就到了Manifest 层,Manifest缓存里有的话, 就直接取,没有的话就去请求。

然后会到HTTP 缓存里面取, 没有的话,就发请求去获取, 服务端根据HTTP的etag 或者Modified Time , 返回304 或者 200 + 数据内容。

性能测试:

开箱即用的插件
offline-plugin

https://lavas.baidu.com/guide...

在测试环境的配置:

// ...
const OfflinePlugin = require("offline-plugin");

// ...

    new OfflinePlugin({
      AppCache: false,                 // 不启用appCache
      safeToUseOptionalCaches: true,   // Removes warning for about `additional` section usage
      caches: {
        main: [
          "**/*.js",
        ],
        additional: [
          ":externals:"
        ]
      },
      externals: [], 
      excludes: ["**/.*", "**/*.map", "**/*.gz", "**/manifest-last.json"],
      autoUpdate: true,
      updateStrategy: "all",
      ServiceWorker: {
        output: "./service-worker.js",       // 输出目录
        publicPath: "/service-worker.js",    // sw.js 加载路径
        scope: "/",                     
        minify: true,                   // 开启压缩
        events: true                    // 当sw状态改变时候发射对应事件
      },
    }),


//  index.html 

import OfflinePluginRuntime from "offline-plugin/runtime";
OfflinePluginRuntime.install({
  // 监听sw事件,当更新ready的时候,调用applyUpdate以跳过等待,新的sw立即接替老的sw
  onUpdateReady: () => {
    console.log("SW Event:", "onUpdateReady");
    OfflinePluginRuntime.applyUpdate();
  },
  onUpdated: () => {
    console.log("SW Event:", "onUpdated");
    window.swUpdate = true;
  },
});

更多信息:

https://juejin.im/entry/5a1c3...
https://lavas.baidu.com/doc/o...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/95541.html

相关文章

  • 前端每周清单年度总结与盘点

    摘要:前端每周清单年度总结与盘点在过去的八个月中,我几乎只做了两件事,工作与整理前端每周清单。本文末尾我会附上清单线索来源与目前共期清单的地址,感谢每一位阅读鼓励过的朋友,希望你们能够继续支持未来的每周清单。 showImg(https://segmentfault.com/img/remote/1460000010890043); 前端每周清单年度总结与盘点 在过去的八个月中,我几乎只做了...

    jackwang 评论0 收藏0
  • 王下邀月熊_Chevalier的前端每周清单系列文章索引

    摘要:感谢王下邀月熊分享的前端每周清单,为方便大家阅读,特整理一份索引。王下邀月熊大大也于年月日整理了自己的前端每周清单系列,并以年月为单位进行分类,具体内容看这里前端每周清单年度总结与盘点。 感谢 王下邀月熊_Chevalier 分享的前端每周清单,为方便大家阅读,特整理一份索引。 王下邀月熊大大也于 2018 年 3 月 31 日整理了自己的前端每周清单系列,并以年/月为单位进行分类,具...

    2501207950 评论0 收藏0
  • 翻译 | Progressive Web AMPs

    摘要:小萝卜沪江前端开发工程师本文原创翻译,有不当的地方欢迎指出。简称就非常擅长做这些,事实这也是它们的宗旨。通过它精心设计的规则能保证优先显示页面的主要内容。原创新书移动前端高效开发实战已在亚马逊京东当当开售。 小萝卜(沪江前端开发工程师)本文原创翻译,有不当的地方欢迎指出。转载请指明出处。 如果你在过去几个月一直关注web开发社区,你很可能已经阅读了 progressive web ap...

    miracledan 评论0 收藏0
  • 前端阅读笔记 2016-11-24

    摘要:话说,今天本来应该有和要学习的,不过时间还是耗在上了。利用实现异步流程控制重温和函数。使用处理图像效果关于中的和。以前还真不知道元素有事件。另外,元素上还有方法,用于自定义提示。时间与日期处理实战这一篇总结得不错。 话说,今天本来应该有 CSS Weekly 和 Web Animation Weekly 要学习的,不过时间还是耗在 Rollup 上了。吐槽一句,Rollup 是很不错,...

    smartlion 评论0 收藏0

发表评论

0条评论

xioqua

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<