-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathlearn_workbox.html
1 lines (1 loc) · 13.9 KB
/
learn_workbox.html
1
<!doctype html><html lang="zh-CN" class="night"><head><meta charset="utf-8"><meta content="width=device-width,initial-scale=1,maximum-scale=4,user-scalable=0" name="viewport"><title>Ede's Blog</title><meta name="description" content="Try to be a qualified programmer"><meta property="og:type" content="website"><meta property="og:description" content="Try to be a qualified programmer"><meta property="og:title" content="Ede's Blog"><meta property="og:site_name" content="Ede's Blog"><meta property="og:url" content="https://ede.ink"><meta property="og:image" content="https://edeity.oss-cn-shenzhen.aliyuncs.com/public/edeity_o.png"><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"><link rel="mainfest" href="/mainfest.json"><link rel="stylesheet" href="/public/css/common.css"><link rel="stylesheet" href="//at.alicdn.com/t/font_707055_4b9og9sc5lx.css"><script>!function(){var e=-1!==window.location.search.indexOf("theme=night")||"night"===window.localStorage.getItem("edeity-theme_theme"),t=-1!==window.location.search.indexOf("theme=light")||"light"===window.localStorage.getItem("edeity-theme_theme");(new Date).getHours();var n=document.querySelector("html");e?n.classList.add("night"):t?n.classList.remove("night"):n.classList.add("night")}(),document.addEventListener("DOMContentLoaded",function(){null!==document.querySelector("ol.toc")&&(document.querySelector("#nav-bar").style.cssText="display: block")})</script><script async src="https://www.googletagmanager.com/gtag/js?id=G-M3J9QSEE2Z"></script><script>function gtag(){dataLayer.push(arguments)}window.dataLayer=window.dataLayer||[],gtag("js",new Date),gtag("config","G-M3J9QSEE2Z")</script><meta name="generator" content="Hexo 5.0.0"></head><body><div class="loading"></div><div id="switch" data-switch="{"toc":true,"use_pwa":false}"></div><header class="fullscreen"><div class="toolbar"><i class="iconfont icon-menu"></i></div><h1><a href="/">Ede's Blog</a></h1><div class="head-link"><a class="btn waves" href="/"><span><i class="iconfont icon-home">Home </i></span></a><a class="btn waves" href="/about/index.html"><span><i class="iconfont icon-me">About </i></span></a><a class="btn waves" target="_blank" rel="noopener" href="https://github.com/edeink"><span><i class="iconfont icon-github">Github</i></span></a></div></header><div class="some-link"><a class="btn" id="light-or-not"><i class="iconfont icon-light"></i> </a><a style="display:none" class="btn" id="up-to-top"><i class="iconfont icon-up"></i></a></div><div id="nav-bar" style="display:none"><div class="toc"><ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%9B%B4%E6%8E%A5%E6%92%B8%E4%BB%A3%E7%A0%81"><span class="toc-number">1.</span> <span class="toc-text">直接撸代码</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BB%80%E4%B9%88%E6%98%AF%E7%BC%93%E5%AD%98%E7%AD%96%E7%95%A5"><span class="toc-number">1.1.</span> <span class="toc-text">什么是缓存策略</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%8B%93%E5%B1%95"><span class="toc-number">2.</span> <span class="toc-text">拓展</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86"><span class="toc-number">2.1.</span> <span class="toc-text">错误处理</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%85%B6%E4%BB%96"><span class="toc-number">3.</span> <span class="toc-text">其他</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%A6%BB%E7%BA%BF%E6%8F%90%E7%A4%BA"><span class="toc-number">3.1.</span> <span class="toc-text">离线提示</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%8A%AF%E4%B8%8B%E7%9A%84%E5%B0%8F%E5%B0%8F%E9%94%99%E8%AF%AF"><span class="toc-number">3.2.</span> <span class="toc-text">犯下的小小错误</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8F%82%E8%80%83%E6%96%87%E7%AB%A0"><span class="toc-number">3.3.</span> <span class="toc-text">参考文章</span></a></li></ol></li></ol></div></div><main id="content-main" class="section"><div class="list-item"><h1 class="post-title"><a id="Workbox3初探:让离线缓存变得简单" class="article-link" href="">Workbox3初探:让离线缓存变得简单</a></h1><div class="post-meta"><time class="meta published">Aug 22, 2018</time></div><div class="warn">鉴于国内PWA比较鸡肋,此博客关闭了PWA,文中部分效果已失效</div><div class="article"><div class="post-excerpt markdown-body"><p>我曾在<a href="/https_your_blog.html">Https你的博客</a>中简单尝试了PWA的离线缓存。</p><p>因为水平有限,在书写<code>service-worker</code>过程中,给我留下了两点不好的印象:</p><ol><li>需要手写所有需要缓存的文件</li><li>不严谨的代码逻辑,可能导致页面更新不及时(<strong>!!包括HTML!!</strong>)</li></ol><p>随后知道了<a target="_blank" rel="noopener" href="https://github.com/GoogleChromeLabs/sw-precache">sw-precache</a>(可以自动生成缓存文件),功能虽然强大,配置却相对麻烦。故觉得PWA有点鸡肋<small>(好吧,我承认,是我智商不够)</small>。直到我遇上了<strong>workbox3</strong>。像是在库海茫茫中遇见了那个“它”,是那么的<strong>简单</strong>,那么的<strong>粗暴</strong>。</p><h2 id="直接撸代码"><a href="#直接撸代码" class="headerlink" title="直接撸代码"></a>直接撸代码</h2><p>启用最基本的Workbox3配置,仅需传入两个参数:</p><ul><li>缓存的文件(正则表达式匹配)</li><li>采取的<strong>缓存策略</strong></li></ul><figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="comment">// 缓存 *.js、*.css、*.html</span></span><br><span class="line">workbox.routing.registerRoute(</span><br><span class="line"> /.*\.(?:js|css|html).*$/,</span><br><span class="line"> workbox.strategies.networkFirst()</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>只需寥寥几行代码,即能赋予站点<code>离线浏览</code>的能力。</p><h3 id="什么是缓存策略"><a href="#什么是缓存策略" class="headerlink" title="什么是缓存策略"></a>什么是缓存策略</h3><p>用正则匹配缓存文件,自不用多说。</p><p>而<strong>缓存策略</strong>则需要解析一下,Workbox3的缓存策略分为五类,分别是: <code>Stale While Revalidate</code>、<code>Network First</code>(网络优先)、<code>Cache First</code>(缓存优先)、<code>Network Only</code>(仅网络可用)、<code>Cache Only</code>(仅缓存可用)。本质就是获取资源,优先显示最新代码,还是缓存代码。</p><p><code>Stale While Revalidate</code>略为特殊,它和<code>Cache First</code>接近,均优先从缓存中读取文件。不同之处在于,<code>Cache First</code><strong>一旦从缓存中获取文件,则不再从服务端请求最新代码</strong>;而<code>Stale While Revalidate</code>,尝试从缓存获取代码并显示执行,但无论缓存命中与否,均<strong>请求网络以更新缓存</strong>。</p><p>故优点是:</p><ul><li>响应及时(优先执行缓存代码,无需等待网络请求返回)</li><li>保证缓存较新(网络请求返回后,及时更新本地缓存,以备下次之需)。</li></ul><p><strong>小打小闹的话,推荐使用<code>Stale While Revalidate;</code></strong></p><h2 id="拓展"><a href="#拓展" class="headerlink" title="拓展"></a>拓展</h2><h3 id="错误处理"><a href="#错误处理" class="headerlink" title="错误处理"></a>错误处理</h3><p>网络不畅时,希望提供比原生404错误更友好的页面。</p><p><a target="_blank" rel="noopener" href="https://github.com/GoogleChrome/workbox/issues/1517">参考github上的讨论</a>,仅需:</p><ul><li><p>首次成功加载页面时,缓存离线资源(eg:<code>img_load_fail.png</code>,<code>offline.html</code>等)</p></li><li><p>后续网络不畅时,通过<code>catch</code>捕获workbox的网络错误,返回之前缓存的离线资源</p></li></ul><p>如:</p><ul><li>访问↓↓<code>未缓存的图片</code>↓↓<small>(在此通过不存在的图片进行模拟)</small>:<img src="/not_exist_img.png" alt="我是不存在的图片"></li></ul><p>或:</p><ul><li>访问未缓存的页面<small>(在此通过不存在的页面进行模拟)</small>:<a href="/not_exist.html">我是不存在的页面</a></li></ul><p>在确保无网络后<small>(可在Chrome的Network中勾选offline)</small>,刷新本页面,查看图片或点击链接,将看到失效的图片或链接,展示为离线资源。</p><p>效果如下:</p><p><img src="https://edeity.oss-cn-shenzhen.aliyuncs.com/2018/offline_img.png" alt="离线访问图片"></p><div class="img-desc">访问图片:在线 Vs离线</div><p><img src="https://edeity.oss-cn-shenzhen.aliyuncs.com/2018/offline_site.png" alt="离线访问未访问的网站"></p><div class="img-desc">访问网站:在线 VS 离线</div>代码如下:<figure class="highlight javascript"><table><tr><td class="code"><pre><span class="line"><span class="comment">// service-worker.js</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 离线访问未缓存的页面时,显示的页面</span></span><br><span class="line"><span class="keyword">const</span> HTML_FAIL_URL = <span class="string">'/public/html/offline.html'</span>; </span><br><span class="line"><span class="comment">// 离线访问未加载的图片</span></span><br><span class="line"><span class="keyword">const</span> IMG_FAIL_URL = <span class="string">'/public/img/img_load_fail.png'</span>; </span><br><span class="line"></span><br><span class="line"><span class="comment">// 处理为访问过的网页URL-HTML</span></span><br><span class="line"><span class="keyword">let</span> networkFirst = workbox.strategies.networkFirst({</span><br><span class="line"> cacheName: <span class="string">'outside-pages'</span></span><br><span class="line">});</span><br><span class="line"><span class="keyword">const</span> offlineHandler = <span class="keyword">async</span> (args) => {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">const</span> response = <span class="keyword">await</span> networkFirst.handle(args);</span><br><span class="line"> <span class="keyword">return</span> response || <span class="keyword">await</span> caches.match(HTML_FAIL_URL);</span><br><span class="line"> } <span class="keyword">catch</span> (error) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">await</span> caches.match(HTML_FAIL_URL);</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line">workbox.routing.registerRoute(</span><br><span class="line"> /.*\.(?:html|php).*$/,</span><br><span class="line"> offlineHandler</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 访问不存在的图片-IMAGE</span></span><br><span class="line"><span class="keyword">const</span> imagesHandler = workbox.strategies.cacheFirst();</span><br><span class="line">workbox.routing.registerRoute(</span><br><span class="line"> /.*\.(?:png|jpg|jpeg|svg|gif).*$/,</span><br><span class="line"> ({event}) => {</span><br><span class="line"> <span class="keyword">return</span> imagesHandler.handle({event})</span><br><span class="line"> .catch(<span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">return</span> caches.match(IMG_FAIL_URL)</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>我博客<code>sw</code>的完整代码:<a target="_blank" rel="noopener" href="https://github.com/edeity/blog/blob/master/themes/edeity/source/sw.v1.js">service-worker.js</a></p><h2 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h2><h3 id="离线提示"><a href="#离线提示" class="headerlink" title="离线提示"></a>离线提示</h3><p>通过监听网络状态,在用户离线瞬间,提示用户:<code>暂时无法连接网络</code>。</p><p>具体方法参考<a target="_blank" rel="noopener" href="https://developer.mozilla.org/zh-CN/docs/Web/API/NavigatorOnLine/Online_and_offline_events">在线和离线事件</a>。在此不展开。</p><h3 id="犯下的小小错误"><a href="#犯下的小小错误" class="headerlink" title="犯下的小小错误"></a>犯下的小小错误</h3><ol><li><code>service-worker.js</code>需放置在根目录下,否则不生效</li></ol><h3 id="参考文章"><a href="#参考文章" class="headerlink" title="参考文章"></a>参考文章</h3><ul><li><a target="_blank" rel="noopener" href="https://developers.google.com/web/ilt/pwa/lab-workbox">Workbox官方教程</a></li><li><a target="_blank" rel="noopener" href="https://developers.google.com/web/tools/workbox/">Workbox官方文档</a></li></ul></div></div></div><div class="more section"><div class="pre"><a class="article-link" href="/learn_png_data.html"><i class="iconfont icon-right"></i> <span>获取PNG中的“分辨率”</span></a></div><div class="next"><a class="article-link" href="/game_for_parkour.html">跑酷小游戏-总结 <i class="iconfont icon-right"></i></a></div></div></main></body><footer class="section fullscreen"><div class="footer-desc">Edeink © 2015-2022 · Powered by Hexo</div></footer><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script><script src="/public/js/init.js"></script></html>