西西河

主题:【原创】PWA,边学边问边用 -- 铁手

共:💬11 🌺59 新:
分页树展主题 · 全看
  • 家园 【原创】PWA,边学边问边用

    PWA: Progressive Web Application. 主推的是GOOGLE,最不卖力的是 APPLE,应该算是最近几年一个比较热门的技术话题。最重要一点是给网站为主的应用提供了一种新的应用方式。

    最近几年来,智能手机为代表的移动上网越来越主流。在智能手机上,大部分人习惯于使用不同的 APP 来达到不同的功能。对于很多的网站来说,面临几个选择。

    1、重起炉灶,在不同平台上用平台工具来写 原生APP,好处是能够充分利用智能手机的软件和硬件环境。一般来说,人机界面,使用效果比较好,比较流畅。

    2、继续利用已经存在的网站程序,在上面加一层包装,然后获得与原生 APP 类似的效果。比如 Cordova,Weex,NativeScript,React Native这一类。尽可能保留已经有的 HTML,JAVASCRIPT,CSS这方面的资源,然后在这个基础上扩展使用移动设备的原生功能。

    3、就是我们要讨论的 PWA方式,主要是通过浏览器功能的强化,还是一个需要浏览器的网站应用,但是具有很多原来哪怕是动态网站也难以实现的动态功能。

    这三种方式都可以成为单独的应用,但是实现的机制不同。PWA的好处,我想是在于它还是一个网站,可以被搜索引擎检索,内容可以通过搜索引擎被发现。举个例子,很多人用微信,在上面有很多内容,但是这些内容没法被搜索,随着时间流逝,相当于就消失了。也就是说,各种独立的 APP,它们里面的内容只能在 APP 里面找,外面没法找,第三方可能也没法找。互联网,特别是网页的好处,是在于内容可以被发现,几乎可以永久存在。

    PWA 是 GOOGLE 在主推,也就很好理解了。既有原生 APP 的使用体验,也能够被搜索引擎检索,应该是 PWA 的重点。能被检索这点不需要担心,重点就是使用体验了。

    所谓渐进 PROGRESSIVE,就是不需要什么都从头来过,而是条件允许就实现一部分功能。

    按照我的理解,PWA主要涉及: Service worker, Manifest, Https。Https 是加密传输,现在费用低了很多,因为安全考虑,应用已经非常广泛,不是大问题。 Manifest 主要涉及到网站资源,也不是大问题。技术上需要费点脑筋的,也就是 Service worker 了。

    下面是我对 Service worker 的理解,有不对请多多指教。有一些疑问,也希望能够得到指点。

    现在很多网站都使用 Javascript来实现很多动态功能。Service worker 也是用 Javascript 来实现。普通的 Javascript 是和各个网页绑在一起,执行也是在各个网页中。Service worker是挂在浏览器里,和网址绑在一起。在某个网址翻看不同页面时,浏览器通过 Service worker 来和网站服务器打交道,当前页面,甚至是相关的页面,以及页面上的各种资源如图片等等,都可以被缓存。

    我的理解,Service worker 就象是代理人。比如以下情形:

    我对 SW 说,我需要 A。

    SW 可以先把手头的 A 给我,然后到库房里再去拿个 A 来下次我要马上就可以给我。

    SW也可以认为手头的 A 有点过期,就先去库房找 A,找到后一边给我一边留个备份。

    我的疑问是,SW来缓存,和浏览器浏览页面的缓存有什么本质区别?浏览器的缓存,还可以在服务器端指定缓存的方式和缓存的有效期。SW也是那样么?

    还有,普通的 Javascript 是当前页面当前执行,如果某个页面关掉了,里面的 Javascript 也就自动失效了。SW 是不是只要有一个页面开着,它就会自动执行,直到某个网址的所有页面都关闭?还是说即使都关闭了,它还能继续执行,除非是浏览器关闭?

    PWA比较强调离线使用。我觉得不是那么重要,而且费劲。比如说离线状态下回复某个帖,多出很多代码来。比较重要的是,能够象 APP 一样安装到用户手机上,点击 APP 的图标就可以直接访问网站。

    SW 提供的 PUSH NOTICE在这里怎么工作?需要还是不需要浏览器就可以在后台进行数据更新?

    我准备慢慢对西西河网站做 PWA的改造,一边学,一边问,一边用。希望能够得到大家指点。

    关键词(Tags): #PWA西西河#Service worker通宝推:南宫长万,tom,
    • 家园 【攻关】Service worker缓存功能,对比和疑问

      多谢几位回复和讨论,@tom,@骆筱,克雷。我花了一段时间看文档和代码,并且试着弄了个 service worker 代码看效果,有一些疑问希望大家讨论,帮助解疑。

      这里先关注 service worker 的缓存功能,其他功能另外会开分枝讨论。

      先看一下目前浏览器的缓存功能,再对照 service worker 的缓存功能,然后试图发现 service worker 的优越性。

      目前浏览器的缓存功能:

      访问一个页面的时候,浏览器可以有两种方式来获得内容。一是在本地缓存找,二是通过网络到服务器去拿。

      浏览器会首先去到本地缓存里找,有的话或者就直接显示了,或者就去问一下服务器要不要更新,没有的话通过网络从服务器来获取。缓存有没有,根据服务器响应得设定来决定。可以通过 Cache-control 或者是 ETag。一般来说,从本地获取总是比通过网络获取来得快。

      为了提高网站性能,一般就是在服务器对各个具体页面设定缓存控制,包括能不能被 CDN 这类代理缓存。

      Service Worker 的缓存机制是在 javascript 代码中利用浏览器的一个新的缓存功能Cache Storage 来实现。比如浏览一个页面时,如果 service worker 从服务器获取内容,可以放到 Cache Storage 里,以后再访问这个页面的时候,就有可能通过 service worker 从 缓存里获得内容。也就是说,以前浏览器自动执行的这些缓存功能,现在需要自己写代码实现缓存的逻辑。好处在哪里,暂时看不出来,有一点优势可能是:浏览器缓存是所有网址共用,service woker操作的缓存是分别对应于各个网站域名,大概可以保证缓存空间足够。

      理想的状态下,我可能希望做到这样的缓存机制:

      服务器端根据页面特性,设置缓存限制:不缓存,缓存定时直接从缓存取,有缓存,但是问服务器有没有过时,过了取新的,否则取本地缓存。

      浏览器干这些已经很在行了,service worker 要自己写代码来实现逻辑。

      service worker 中怎么弄?是不是需要如下的做法?

      1、 caches.match(cacheRequest);

      如果没内容,则 走网络 fetch。

      如果有内容,对返回查看 cache-control (怎么查看?),然后根据结果决定是不是去服务器取内容。如果不需要,内容直接显示。如果需要,则 走网络fetch。

      2、fetch(fetchRequest);

      fetch 返回的 response,新内容好说,显示并且缓存。有没有可能缓存中有内容,服务器返回的是 304 Not Modified 内容没有变更?需要检查返回的状态码么?还是说 fetch 本身就已经实现了这些缓存逻辑?只需要返回 fetch 的 response 就可以?

      目前我试验了两种方式。

      一种是先 fetch 并缓存,有错则通过缓存 match。我的理解是,有网情况下,和没有 service-work工作方式类似,但是每次都需要通过网络从服务器取,不能利用本地缓存快速响应。好处是无网的情况下,本地缓存内容可以显示出来。

      还有一种是先 match ,有错则 fetch 并缓存。我的理解是,有网无网,有缓存就都有内容显示。有网的情况下,缓存也得不到更新,因为没有机会 fetch。如果缓存没内容,fetch 普通页面没问题,但是 ajax要取的页面首先返回网络超时,再来一次则有内容。是不是对 ajax 的页面请求需要

      event.waitUntil(event.respondWith(....

      顺便说一下,navigator.serviceWorker.register("/sw.js") 时候,它的作用范围在 service worker js 文件目录及以下子目录,可以设定更小的范围,但是不能设定更大的范围。比如 /aaa/sw.js 的作用范围没有办法设定到 /。我本来想集中这些到一个子目录然后作用到网站所有目录,直觉是对的,操作不能。这个规则不是那么直白,提个醒。

      下面是测试 先网络取,本地缓存为后备的代码。怎么有效改为缓存为先,必要的话网络。

      self.addEventListener('fetch', function(evt) {
       // Clone the request for fetch and cache
       // A request is a stream and can be consumed only once.
       var fetchRequest = evt.request.clone(),
       cacheRequest = evt.request.clone();
       if (evt.request.method === 'GET') {
       // Respond with content from fetch or cache
       evt.respondWith(
       // Try fetch
       fetch(fetchRequest)
       // when fetch is successful, we update the cache
       .then(
       function(response) {
       // A response is a stream and can be consumed only once.
       // Because we want the browser to consume the response,
       // as well as cache to consume the response, we need to
       // clone it so we have 2 streams
       var responseToCache = response.clone();
       // and update the cache
       caches
       .open(CACHE)
       .then(function(cache) {
       // Clone the request again to use it
       // as the key for our cache
       var cacheSaveRequest = evt.request.clone();
       cache.put(cacheSaveRequest, responseToCache);
       });
       // Return the response stream to be consumed by browser
       return response;
       }
       )
       // when fetch times out or fails
       .catch(
       function(err) {
       // Return the promise which
       // resolves on a match in cache for the current request
       // ot rejects if no matches are found
       return caches.match(cacheRequest);
       }
       )
       );
       }
      });
      
      关键词(Tags): #Service worker
      • 家园 看了更多文档,自己也做了一些测试

        现在看来,fetch 对缓存的功能和浏览器一样,浏览器怎么做,fetch怎么做。

        那么,用 service worker 的时候,网络优先,缓存第二的策略下,浏览器会有一份缓存,在 service worker 里管理的另外又有一份缓存。桌面可能问题不大,硬盘空间现在都很大。在手机上可能会有一些不利,手机上的存储空间很宝贵。而且,Cache Storage 里面的内容怎么定期清除老的缓存项,而不是全部清除?

        chrome 的开发调试工具里,fetch 返回的状态码,即使是缓存中来,也是 200,而不是304,有点误导人。

    • 家园 感觉就是chrome extension换了个外套

      Manifest,注册到浏览器绑定而不是网页,这些都是一样的。也是用JS,html,css.

      不能标准化的这些新概念,只是让移动开发更碎片化了,建议谨慎,被google大力鼓吹最后丢弃的项目不是一两个。

      • 家园 我理解PWA是一个设计模式 design pattern

        类似于MVC, MVVM,本身只有流行不流行,没有标准不标准的问题。

        为了支持这些框架的流行,往往会推动一些基本技术的标准化,尤其Google喜欢这个套路推广chrome。

        现在google和微软的开发部门关系很好,比如google帮推typescript, 两家一起搞 PWA, web assembly。 Apple被动跟上。

        PWA的基本技术service worker, fetch 之类可以算是标准了,只是要比较新的浏览器版本。

      • 家园 目前看来这个PWA会持续下去

        现在微软也很卖力,按照它的说法,以后PWA的网站,BING在检索的时候,可以自动转换为 windows app 放到它的 windows store 里面。虽然现在 windows store相比 APPLE 和 ANDROID 来说是鸡肋,架不住它还是桌面系统的主要玩家。

        APPLE 的浏览器也开始支持里面涉及的技术了,最后能不能直接上 APPLE 的 APP STORE,还是个问题。

        其实象我这样的,最关心就是省时省力,能够象个 APP。PWA的概念我觉得很好,技术实现的确是还觉得有些地方不好理解。不过,从你说的 extension的角度来看,似乎就好理解了。

    • 家园 说说我的理解

      先把JS放一边。网站的最简单数据流程是浏览器1)从网站拉取数据 2)建立DOM树呈现出来。这原本是一体化的工作,随着技术和需求的发展,内部细节需要更多开放,和定制化挂点。

      好比以前是一个整体的exe文件,现在逐步重构发展成一组dll协同工作,分离出越来越多的调用栈。根据数据流,这些dll的调用顺序有先后,有重叠,有并行,所以数据的处理流程从原来的顺序为主,开始有更多的分支和循环。

      现在流行的做法是把这些独立出来的功能栈叫做worker, 使用方式就是先register,来挂载到浏览器原来的流程,这样保证了兼容:挂上去了就替换成新功能,不挂就跟以前一样。

      同样实现思路的还有web assembly. 他们都有一个特点,不能跟DOM直接打交道,我把这理解成因为DOM属于另外一个worker(标准术语不这么叫)。

      由于JS是跟浏览器内部实现的标准语言,所有的挂载点以JS API提供,所以反而模糊这种层次界限。

      按这么理解,现在的PWA就是以前缓存机制的现代版本,以最新的技术解决老需求。

      除了骆筱提到的的技术层面细节,PWA还有一个很大市场卖点,是和移动操作系统的集成,尤其是其通知机制,所以对终端用户,其行为很像app,对开发者又很容易更新内容。push notice是操作系统的功能,浏览器调用它的功能,集成包装一下,留下一个挂载点给开发者。

      通宝推:铁手,
      • 家园 webassembly是高效二进制代码的js实现

        和PWA这样架构上对浏览器功能的扩充不是一回事。用WebAssembly可以把很多原来用C/C++实现的高级库直接移植到现代浏览器中执行,比如3D、图像视频的实时处理、机器学习等等。最近所谓edge computing,把一部分高负荷处理放在客户端分散处理的一种趋势。PWA中也可融合使用WebAssembly。

        PWA降低了开发难度,提高了和用户接触的机会(网站->驻留),便于推广。service worker就是为了PWA解决动态更新的一种技术手段。

        • 家园 我指的是WASM这种需求的切入方式

          在现有浏览器对内部功能的调用只能是JS,这是很多解决方案的出发点。

          WASM本质上是提供一种异于JS的选择,好处是可以提供更高的效率,最开始是C++, 现在Rust和.net都有人搞,越来越像基于浏览器的llvm。

          所以你看,就执行方式而言,对于PWA,你用JS写一些逻辑,注册到浏览器后,它启一个Workers来运行。

          对于WASM,不管你是C++, Rust还是C#写,先编译成一段字节代码, 浏览器装载(Load)后运行。

          真正的区别在于,前者都是JS, 所以注册,后者对JS来说是字节,所以是加载

          今天看到一篇杨振宁的采访,他提到了近看和远看两种方式。

          你说的全都对,但可能你更多拉近了看,我更多拉远了看。

    • 家园 service worker的生存周期

      service worker是独立于网页的,有单独的线程,有自己的生存周期,安装激活后响应(fetch/message)其管理scope下的网页发出的请求。这个可以参见https://developers.google.com/web/fundamentals/primers/service-workers/?hl=en

      另外Safari也已经正式支持service worker。

      Service Worker激活后一直在后台运行,因为是事件响应型非同期执行的,既不会一直高消耗CPU,也不会阻止(block)网页的正常渲染和执行脚本。

      原来有Offline Web Application提供AppCache,仅能用manifest文件来比较简单地控制web应用的资源缓存,这已经比浏览器提供的缓存提供了更多控制:有效期间、版本等。而Service Worker实际上可以认为是可编程缓存管理系统,提供更细致的粒度和对动态请求的支持,当然还包括Notification在内的其他功能。

      通宝推:铁手,
分页树展主题 · 全看


有趣有益,互惠互利;开阔视野,博采众长。
虚拟的网络,真实的人。天南地北客,相逢皆朋友

Copyright © cchere 西西河