资讯专栏INFORMATION COLUMN

Service Worker 图片加载失败处理

huaixiaoz / 2360人阅读

摘要:图片加载失败处理参考文档运行访问打开控制台刷新由于做的是后加载需刷新后看效果结束服务再次刷新页面从缓存里面读取依然显示页面简介背景有一个困扰用户多年的难题丢失网络连接。一旦新的接管,则会触发事件。

Service Worker 图片加载失败处理

参考文档

git clone https://gitee.com/wjj0720/Service-Worker.git
运行 npm i 
npm start
访问 http://127.0.0.1:3000/pages/index.html  

打开控制台  刷新(由于demo做的是后加载 需刷新后 看效果)

ctrl + c 结束node服务 再次刷新页面(从缓存里面读取 依然显示页面)
简介

背景

有一个困扰 web 用户多年的难题——丢失网络连接。之前的尝试 — AppCache — 看起来是个不错的方法,但是,它假定你使用时会遵循诸多规则,如果你不严格遵循这些规则,它会把你的APP搞得一团糟。Service worker 最终要去解决这些问题。虽然 Service Worker 的语法比 AppCache 更加复杂,但是你可以使用 JavaScript 更加精细地控制 AppCache 的静默行为。有了它,你可以解决目前离线应用的问题,同时也可以做更多的事。 Service Worker 可以使你的应用先访问本地缓存资源,所以在离线状态时,在没有通过网络接收到更多的数据前,仍可以提供基本的功能(一般称之为 Offline First)。这是原生APP 本来就支持的功能,这也是相比于 web app,原生 app 更受青睐的主要原因。

什么是Service Worker ?

Service Worker是浏览器在后台启动的一条服务Worker线程

功能和特性:

  1.一个独立的 worker 线程,且只有一个。
  2.一旦被 install,就永远存在,除非被 uninstall
  3.需要的时候可以直接唤醒,不需要的时候自动睡眠(此处有坑)
  4.可代理请求和返回,缓存文件,缓存的文件可以被网页进程取到
  5.能向客户端推送消息
  6.不能直接操作 DOM
  7.出于安全的考虑,必须在 HTTPS/localhost  环境下才能工作
  8.异步实现,内部大都是通过 Promise 实现
  9.基于[web worker](http://www.ruanyifeng.com/blog/2018/07/web-worker.html)

使用

1.注册

    // 兼容判断
   if ("serviceWorker" in navigator) {
    // 一般考虑加载问题 windoe.onload后加载
    window.addEventListener("load", function() {
      // scope 参数是选填的,可以被用来指定你想让 service worker 控制的内容的子目录
      navigator.serviceWorker.register("/sw.js", {scope: "/"})
        .then(function(registration) {
          // 注册成功
          console.log( "ServiceWorker registration successful with scope: ", registration.scope )
        })
        .catch(function(err) {
          // 注册失败
          console.log("ServiceWorker registration failed: ", err)
        });
    })
  }

2.使用

    const precacheVersion = 2
    const precacheName = "precache-v" + precacheVersion
  
    var precacheFiles = [
      "/pages/index.html",
      "/images/dmx.jpg",
      "/images/broken.png"
    ]


/*更新
 *  SW.js 浏览器会自动检查差异性 
 * 发生变更 install 事件被触发 此时,旧的 SW 还在工作,新的 SW 进入 waiting 状态。
 * 注意,此时并不存在替换接管,当你现在已经打开的页面关闭时,那么旧的 SW 则会被 kill 掉。
 * 新的 SW 就开始接管页面的缓存资源。 一旦新的 SW 接管,则会触发 activate 事件。 
*/

self.addEventListener("install", e => {
  console.log("[ServiceWorker] Installed")
// skipWaiting() 方法跳过 waiting 状态,然后会直接进入 activate 阶段
  self.skipWaiting()

  e.waitUntil(
    caches.open(precacheName).then(cache => {
      // 如果其中有一个 加载失败 那就代表着--这次启动 GG  
      return cache.addAll(precacheFiles)

      // cache.put(request, response).then(function() {
      //   // 成功缓存
      // });
    })
  ) 
})

self.addEventListener("activate", e => {
  console.log("[ServiceWorker] Activated")

  e.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.map(thisCacheName => {
          if ( thisCacheName.includes("precache") && thisCacheName !== precacheName ) {
            return caches.delete(thisCacheName)
          }
        })
      )
    })
  )

  // 更新客户端
  // self.clients.claim()

})


// 监听页面的请求 (不仅仅是js请求)
self.addEventListener("fetch", e => {
  e.respondWith(
    caches.match(e.request).then(response => {
      // 有缓存走缓存
      if (response) {
        return response
      }

      return fetch(e.request) .then(fetchResponse => {

        // console.log("s-->", fetchResponse);
        if (fetchResponse.ok) return fetchResponse;
        // 加载失败的情况下 入股是图片 则返回默认图片
        if (isImage(e.request)) {
          return returnBrokenImg()
        }

        
      }).catch(err => {
        if ( isImage(e.request) ) {
          return returnBrokenImg()
        }
      })
    })
  )
})

function isImage(fetchRequest) {
  return fetchRequest.method === "GET" && fetchRequest.destination === "image";
}

function returnBrokenImg () {
  return caches.match("/images/broken.png").then(response => response)
}


// 监听页面发来的消息
self.addEventListener("message", function (message, e) {
  console.log("service接受到的数据--->", message, e);
  sendMessageToPage("嘟嘟嘟")
});

// 向页面发送消息
function sendMessageToPage (msg) {

  self.clients.matchAll().then(function (clients) {
    if (clients && clients.length) {
      clients.forEach(function (client) {
        client.postMessage(msg);
      })
    }
  })
}

3.客户端更新

除了由浏览器触发更新之外,如果24小时没有更新,会强制更新。这意味着最坏情况下Service Worker会每天更新一次
  //客户端更新方法: localStorage 存下 版本  运行时候对比
  var version = "precache-v3"
  navigator.serviceWorker.register("/sw.js").then(function (reg) {
    if (localStorage.getItem("sw_version") !== version) {
      reg.update().then(function () {
        localStorage.setItem("sw_version", version)
      });
    }
  })

4.客户端消息

  // 监听serviceWorker 消息
  navigator.serviceWorker.addEventListener("message", function (event) {
      // 接受数据,
      console.log("页面接受的数据:",  event);
  });
  // 发送消息
  document.getElementById("sendMSG").addEventListener("click", function () {
      console.log("绑定点击事件,点击后发送数据");
      navigator.serviceWorker.controller.postMessage("嘀嘀嘀");
  });

应用案例

  1. 拦截图片加载失败 返回默认图片 案例 https://bitsofco.de/handling-broken-images-with-service-worker/
  2. 蓝湖 https://lanhuapp.com/

新鲜货

https://github.com/jiahaog/na...

https://imgcook.taobao.org/pr...

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

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

相关文章

  • JavaScript 工作原理之八-Service Workers,生命周期及其使用场景

    摘要:生命周期的生命周期和网页完全不相关。意即会作用于整个源地址上。激活安装完之后下一步即激活。同时检查响应类型是否为,即检查请求是否同域。创建新的的过程将会启动,然后触发事件。可以利用劫持网络连接和伪造响应数据。 原文请查阅这里,略有删减,本文采用知识共享署名 4.0 国际许可协议共享,BY Troland。 本系列持续更新中,Github 地址请查阅这里。 这是 JavaScript 工...

    oysun 评论0 收藏0
  • 构建 Web 应用之 Service Worker 初探

    摘要:诞生之初,是单线程的。当接收到服务端的响应之后,便通过回调函数执行之后的操作。冲锋基于事件驱动。拥有拦截请求消息推送静默更新地理围栏等服务。控制时处于两种状态之一终止以节省内存监听获取和消息事件。支持的所有事件五销毁浏览器决定是否销毁。 这次体验一种新的博客风格,我们长话短说,针针见血。 showImg(https://segmentfault.com/img/remote/14600...

    voidking 评论0 收藏0
  • Service Worker 浅析

    摘要:可以发送通知消息以再次吸引用户并留住他们。在即时通讯等使用情形中,一条消息可将最多的有效负载传送至客户端应用。浏览器的的消息推送主要依赖,服务端消息推送传递到,然后再由推送到客户端。 引言 Progressive Web App, 简称 PWA,是提升 Web App 的体验的一种新方法,能给用户原生应用的体验。Service Worker 是 PWA 中的重要一部分。Service ...

    The question 评论0 收藏0

发表评论

0条评论

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