前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >pwa-之service worker 基本概念

pwa-之service worker 基本概念

作者头像
frontoldman
发布于 2019-09-03 08:13:51
发布于 2019-09-03 08:13:51
1.1K00
代码可运行
举报
文章被收录于专栏:樯橹代码樯橹代码
运行总次数:0
代码可运行

pwa-之service worker 基本概念

pwa-之service worker 离线文件处理

学习service worker 基本概念

在本章,将涵盖以下内容

  • service worker准备工作
  • 注册service worker
  • 注册service worker细节
  • 调试
  • 出现错误时提供稳定版本
  • 创建mock响应
  • 处理请求超时

简介

如果你是一个旅行爱好者,应该会经常陷入没有网络的情况。这是令人沮丧的。特别是你有事情的时候。

service worker是一个在==浏览器后台==运行的脚本。无论网络连接如何,能够使用Web应用程序意味着用户可以在飞机,地铁或连接受限或不可用的地方不间断地操作。 该技术将有助于提高客户端的工作效率,并将提高应用程序的可用性。

通过service worker,我们可以预先缓存网站的某些资源。 我们作为资源引用的是JavaScript文件,CSS文件,图像和一些字体。 这将有助于我们加快加载时间,而不必每次访问同一网站时都必须从服务器获取。 当然,最重要的是,当我们网络不畅时,这些资源将可供我们使用。

Service workers

service worker是浏览器和服务器之间的脚本,主要作用是拦截请求,修改响应,以及一些其他的作用。

网站可以正常工作的前提是能获取到html,css,js等资源。在之前这些资源主要由浏览器管理,对于开发者而言是不可见的。现在通过service worker我们可以掌控这些资源。当然最终还是通过浏览器控制他们的。

掌握service worker的前提是掌握promise

Promise

Promise是用于处理异步操作的很好的方式,对于掌握service worker是至关重要的。

Promise功能很强大,我们不在这里细述了。我们只需要知道调用then()方法处理成功,catch方法处理错误就可以了。

一个简单的比较同步和异步操作的代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
sync
    try {
        var value = Fn();
        console.log(value);
    } catch(err) {
        console.log(err);
    }
    
async
    Fn()
    .then(function(value) {
        console.log(value);
    })
    .catch(function(err) {
        console.log(err);
    });

service worker准备工作

Service workers能够运行的前提是网站采用了https。这是出于安全因素的考虑。

现在主流浏览器都已经支持service worker,不需要去单独开启了。

虽然service worker一定要在https的域名下面运行,但是本地的http://localhost域名却不影响,可以正常运行。

注册service worker

一个service worker如果要生效,必须要先注册。这个注册的过程是发生在service worker之外的。一般会在index.html中。你可以写在js文件里面,在html文件中引入,但不能在service worker的js中注册。

如何注册

  1. 先创建一个html文件
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!DOCTYPE html>
<html lang="en">
<head></head>
<body>
    <p>Registration status: <strong id="status"></strong></p>
    <script>
    if ('serviceWorker' in navigator) {
        navigator.serviceWorker.register(
            'service-worker.js',
            { scope: './' }
        ).then(function(serviceWorker) {
            document.getElementById('status').innerHTML = 'successful';
        }).catch(function(error) {
            document.getElementById('status').innerHTML = error;
        });
    } else {
        document.getElementById('status').innerHTML = 'unavailable';
    }
    </script>
</body>
</html>
  1. 在当前文件夹下面创建一个==名字叫service-worker.js==的js文件
  2. 启动一个本地服务器,推荐使用anywhere,自带了https

成功图示

undefined(http://wx2.sinaimg.cn/mw690/0...

)

程序如何运行

首先判断浏览器支持情况,如果不支持则做出提示。

我们使用了空js文件注册了service worker。register的第二个参数的scope表示此service worker的作用范围是当前域名下面的根目录。

如图显示:注册成功。说明我们的浏览器是支持service worker的。

卸载service worker

通过调用unregister()方法卸载service worker

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
serviceWorker.unregister().then(function() {
    document.getElementById('status').innerHTML = 'unregistered';
})

注册service worker的详细信息

了解service worker注册过程中的详细信息和事件有助于我们更好的掌控它。

注册详情

  1. 我们创建一个如下的html页面
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Detailed Registration</title>
</head>
<body>
  <p>Registration status: <strong id="status"></strong></p>
  <p>State: <strong id="state"></strong></p>

  <script>
    function printState(state) {
      document.getElementById('state').innerHTML = state;
    }

    if ('serviceWorker' in navigator) {

      navigator.serviceWorker.register(
        'service-worker.js',
        { scope: './' }
      ).then( function(registration) {
        var serviceWorker;

        document.getElementById('status').innerHTML = 'successful';

        if (registration.installing) {
          serviceWorker = registration.installing;
          printState('installing');
        } else if (registration.waiting) {
          serviceWorker = registration.waiting;
          printState('waiting');
        } else if (registration.active) {
          serviceWorker = registration.active;
          printState('active');
        }

        if (serviceWorker) {
          printState(serviceWorker.state);

          serviceWorker.addEventListener('statechange', function(e) {
            printState(e.target.state);
          });
        }
      }).catch(function(error) {
        document.getElementById('status').innerHTML = error;
      });
    } else {
        document.getElementById('status').innerHTML = 'unavailable';
      }
  </script>
</body>
</html>
  1. 创建一个service-worker.js文件
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
self.addEventListener('install', function(e) {
  console.log('Install Event:', e);
});

self.addEventListener('activate', function(e) {
  console.log('Activate Event:', e);
});
  1. 然后页面如下显示

程序如何运行

上面的代码描述了service worker的3种状态。当程序处于active状态的时候,我们就可以刷新页面查看处于service worker控制之下的页面了。

在service worker中我们注册了两个事件,installactivate,当service worker第一次注册的时候会被触发。

install事件比较适合用来预加载数据和初始化缓存,activate事件适合用来清理旧版本的数据。

其他

当一个service worker被成功注册,它会经历以下状态

Install

在service worker的生命周期中,如果service worker已经注册没有错误,但是尚未激活。那之前已经激活的service worker就会仍然会控制着页面。重新加载之后的service worker如果发生任何更改,就会重新安装service worker。在安装完成,激活之前,它不会拦截任何请求。

Activate

当service worker被激活时,它的状态就是activate。service worker就可以拦截请求了。只有当我们关闭网页重新打开,或者强制刷新当前页面,才会被激活。一般安装成功之后不会立即处于activate状态。

Fetch

在当前scope作用域下面的请求会触发fetch事件

Terminate

这个事件可能会发生在任何时候,主要后果就是需要浏览器做service worker的内存回收。之后根据需要重启,但不是不会在触发activate事件。

service worker将会始终拦截请求,重启页面也是为了这个。虽然这么说,但我们无法保证service worker任何时候都处于生效状态,所以在service worker中定义的全局状态可能不会被保留。所以我们最好使用indexDB和localStorage来实现持久化。

调试

service worker在浏览器中单独线程运行,通过单独的方式和页面通信。但是和页面是处于不同的作用域。这就意味着service worker无法访问网页的dom等其他信息。因此我们也无法通过

DevTools里面同一个tab来调试service worker。我们需要一个单独的Tab来调试service worker线程。

在service worker中,它大部分的工作是在监听的事件中来完成的,比如在install事件中完成资源缓存。同样我们可以在这里打断点。

怎么做

下面来展示如何调试

  1. 在chrome中打开:chrome://inspect/#service-workers
  1. 或者在chrome中输入:chrome://serviceworker-internals/ 如果列表里面没有的话,说明没有service worker正在运行
  1. 在DevTools中的Source下面的service worker可以看到对应的js脚本
  2. 在这里可以调试

同样可以使用console.log

  1. chrome://serviceworker-internals/页面中,可以看到每个service worker下面有几个按钮。
  2. Terminated:注销service worker
  3. Start/Stop: 开启/停止service worker
  4. Sync: 给worker同步Sync事件
  5. push: 给worker同步push事件
  6. Inspect:在检查器中打开worker

==即使勾选了Network中的disable cache,service worker依然会生效,如果需要每次都更新,需要勾选Application->service worker->offline==

发生错误时提供稳定版本

  1. 创建一个html文件
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Stale on Error</title>
</head>
<body>
  <p>Registration status: <strong id="status"></strong></p>
  <script>
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker.register(
        'service-worker.js',
        { scope: './' }
      ).then( function(serviceWorker) {
        document.getElementById('status').innerHTML = 'successful';
      }).catch(function(error) {
        document.getElementById('status').innerHTML = error;
      });

    } else {
      document.getElementById('status').innerHTML = 'unavailable';
    }
  </script>
</body>
</html>
  1. 创建service-worker.js文件
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var version = 1;
var cacheName = 'stale-' + version;

self.addEventListener('install', function(event) {
    self.skipWaiting();
});

self.addEventListener('activate', function(event) {
    if (self.clients && clients.claim) {
        clients.claim();
    }
});

self.addEventListener('fetch', function(event) {
    // Always fetch response from the network
    event.respondWith(
        fetch(event.request).then(function(response) {
            return caches.open(cacheName).then(function(cache) {
                // If we received an error response
                if(response.status >= 500) {
                    return cache.match(event.request).then(function(response) {
                        // Return stale version from cache
                        return response;
                    }).catch(function() {
                        // No stale version in cache so return network response
                        return response;
                    });
                } else {
                    // Response was healthy so update cached version
                    cache.put(event.request, response.clone());
                    return response;
                }
            });
        })
    );
});

当网络中断之后,页面依然可以访问。

创建mock响应

我们可以模拟服务器,对客户端进行响应。

  1. 创建index.html页面
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Detailed Registration</title>
</head>
<body>
  <p>Network status: <strong id="status"></strong></p>
  <div id="request" style="display: none">
    <input id="long-url" value="https://www.packtpub.com/" size="50">
      <input type="button" id="url-shorten-btn" value="Shorten URL" />
    </div>
    <div>
      <input type="checkbox" id="mock-checkbox" checked>Mock Response</input>
    </div>
    <div>
      <br />
      <a href="" id="short-url"></a>
    </div>
  </div>

  <script>
    function printStatus(status) {
      document.getElementById('status').innerHTML = status;
    }

    function showRequest() {
      document.getElementById('url-shorten-btn').addEventListener('click', sendRequest);
      document.getElementById('request').style.display = 'block';
    }

    function sendRequest() {
      var xhr = new XMLHttpRequest(),
        request;

      xhr.open('POST',
        'https://www.googleapis.com/urlshortener/v1/url?key=AIzaSyCr0XVB-Hz1ohPpjvLatdj4qZ5zcSohHsU');
      xhr.setRequestHeader('Content-Type', 'application/json');

      if (document.getElementById('mock-checkbox').checked) {
        xhr.setRequestHeader('X-Mock-Response', 'yes');
      }

      xhr.addEventListener('load', function() {
        var response = JSON.parse(xhr.response);
        var el = document.getElementById('short-url');

        el.href = response.id;
        el.innerHTML = response.id;
      });

      request = {
        longUrl: document.getElementById('long-url').value
      };

      xhr.send(JSON.stringify(request));
    }

    if ('serviceWorker' in navigator) {

      navigator.serviceWorker.register(
        'service-worker.js',
        { scope: './' }
      ).then( function(registration) {
        if (navigator.serviceWorker.controller) {
            printStatus('The service worker is currently handling network operations.');
            showRequest();
          } else {
            printStatus('Please reload this page to allow the service worker to handle network operations.');
          }
      }).catch(function(error) {
        document.getElementById('status').innerHTML = error;
      });
    } else {
        document.getElementById('status').innerHTML = 'unavailable';
      }
  </script>
</body>
</html>
  1. 创建service-worker.js
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
self.addEventListener('fetch', function(event) {
  var requestUrl = new URL(event.request.url);

  if (requestUrl.pathname === '/urlshortener/v1/url' &&
      event.request.headers.has('X-Mock-Response')) {

    var response = {
      body: {
        kind: 'urlshortener#url',
        id: 'https://goo.gl/KqR3lJ',
        longUrl: 'https://www.packtpub.com/books/info/packt/about'
      },
      init: {
        status: 200,
        statusText: 'OK',
        headers: {
          'Content-Type': 'application/json',
          'X-Mock-Response': 'yes'
        }
      }
    };

    var mockResponse = new Response(JSON.stringify(response.body), response.init);

    console.log('Mock Response: ', response.body);
    event.respondWith(mockResponse);
  }
});

可以看到页面显示的是service worker里面我们配置的响应

处理请求超时

请求超时有可能是网络连接的问题,service worker是解决这类问题的理想方案。

  1. 创建html文件
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Request Timeouts</title>
</head>
<body>
  <p>Registration status: <strong id="status"></strong></p>

  <script>
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker.register(
        'service-worker.js',
        { scope: './' }
      ).then(function(serviceWorker) {
        document.getElementById('status').innerHTML = 'successful';
      })
    } else {
      document.getElementById('status').innerHTML = 'unavailable';
    }
  </script>

  <script src="https://code.jquery.com/jquery-2.2.0.js"></script>
</body>
</html>
  1. 创建service-worker.js
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function timeout(delay) {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            resolve(new Response('', {
                status: 408,
                statusText: 'Request timed out.'
            }));
        }, delay);
    });
}

self.addEventListener('install', function(event) {
    self.skipWaiting();
});

self.addEventListener('activate', function(event) {
    if (self.clients && clients.claim) {
        clients.claim();
    }
});

self.addEventListener('fetch', function(event) {
  if (/\.js$/.test(event.request.url)) {
    event.respondWith(Promise.race([timeout(400), fetch(event.request.url)]));
  } else {
    event.respondWith(fetch(event.request));
  }
});

当我们把jquery地址换成一个错误的地址,我们看到一个408的响应。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
手把手教你实现一个图片压缩工具(Vue与Node的完美配合)
图片压缩对于我们日常生活来讲,是非常实用的一项功能。有时我们会在在线图片压缩网站上进行压缩,有时会在电脑下软件进行压缩。那么我们能不能用前端的知识来自己实现一个图片压缩工具呢?答案是有的。
Vam的金豆之路
2021/12/01
8060
手把手教你实现一个图片压缩工具(Vue与Node的完美配合)
H5图片压缩与上传
现在手机用户拍照照片都十分巨大,1m-10m,而普通用户的上传带宽大概为100kb/s-1m/s,导致上传图片十分缓慢
仙士可
2019/12/19
2K0
H5图片压缩与上传
"图像瘦身术":Java借助Tinify轻松将4M图片压缩至1M
在当今的数字化时代,图片已成为网站、应用和社交媒体中不可或缺的元素。然而,大尺寸的图片不仅会增加页面或者客户端加载时间,还会占用大量的存储空间。为了解决这个问题,可以使用图片压缩工具来减小图片的尺寸,然后再将压缩后的图片上传至对象存储服务(如阿里云OSS)。本文将详细介绍如何利用Tinify压缩图片,并将其上传至OSS,重点介绍图片压缩实现方式。
小明爱吃火锅
2024/09/23
5350
​PNG图片压缩对比分析
随着版本的迭代,业务的增加,QQ音乐apk的大小已经超过25M,其中res目录占用的大小超过5.5M,所以提出了对安装包进行瘦身的技术需求。
QQ音乐技术团队
2018/02/01
10.1K0
​PNG图片压缩对比分析
手把手教你实现一个Vue无限级联树形表格(增删改)
平时我们可能在做项目时,会遇到一个业务逻辑。实现一个无限级联树形表格,什么叫做无限级联树形表格呢?就是下图所展示的内容,有一个祖元素,然后下面可能有很多子孙元素,你可以实现添加、编辑、删除这样几个功能。
马克社区
2022/05/11
1.5K0
localResizeIMG图片压缩上传 原
(adsbygoogle = window.adsbygoogle || []).push({});
tianyawhl
2019/04/04
1.4K0
localResizeIMG图片压缩上传
                                                                            原
Typecho增加评论图片
代码 // 评论图片 $CommentImg = new Typecho_Widget_Helper_Form_Element_Select(
小东东
2023/03/20
1K0
Typecho增加评论图片
《Nuxt.js 实战:从放弃到入门》三、超实用! 打造图片压缩神器
代码托管地址:https://github.com/outeasy/outeasy/releases/tag/v0.3
小码农薛尧
2025/02/20
860
《Nuxt.js 实战:从放弃到入门》三、超实用! 打造图片压缩神器
直播视频网站源码,多媒体图片压缩工具类
以上就是 直播视频网站源码,多媒体图片压缩工具类相关的代码,更多内容欢迎关注之后的文章
yunbaokeji柯基
2021/01/06
7490
直播视频网站源码,多媒体图片压缩工具类
图片上传预览插件制作思路及Demo分享
一旦选择的路径被改变就把图片上传至服务器,然后就返回图片在服务器端的地址,并且赋值到img元素上。
winty
2019/12/26
1.4K0
element ui 图片上传封装多张或单张
最近写了一个后台管理项目,发现每个后台项目都离不开上传图片,决定把上传图片做个封装,话不多说直接上代码!
前端小白@阿强
2020/08/11
2.4K0
Vue 图片上传组件(base64 版):vue-upload-imgs
vue-upload-imgs 上传组件保存的是图片的 base64 码,这是项目地址,欢迎关注。
谭光志
2020/09/28
1.1K0
vue.js + axios.js图片压缩处理并上传到服务器demo
点击查看效果 图片压缩原理 将图片重新画入一个canvas中。可设置最大宽度,再按图片宽高比例定义canvas画布的宽高。 完整代码demo <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>上传图片</title> <meta name="renderer" content="webkit"> <meta name="viewport" content="widt
别盯着我的名字看
2022/06/09
5.6K0
开发实例:后端Java和前端vue实现图片管理功能
2. 通过input[type=file]元素上传图片,使用element-ui的Upload组件进行封装。
用户1289394
2024/01/19
6960
开发实例:后端Java和前端vue实现图片管理功能
vue+vue-cropper实现上传剪裁图片以及上传时压缩图片
代码暂时都是从项目中抽出来的,只适合借鉴参考,等有时间再单独将这些功能单独写项目,欢迎大家提供更好用的方法或指出不足之处,一起进步。
conanma
2021/11/03
3.7K0
使用Vue封装一个实用的人脸识别组件
由于我们的电脑有的有摄像头,有的没有摄像头,所以我们需要根据不同的场景来封装这个组件。先放个图吧,大家可以看得更加直观一些。
Vam的金豆之路
2021/11/30
3.5K1
使用Vue封装一个实用的人脸识别组件
Nodejs实现图片的上传、压缩预览、定时删除。
这里我们用到的是koa框架,它可是继express框架之后又一个更富有表现力、更健壮的web框架。
Vam的金豆之路
2021/11/30
1.5K0
Nodejs实现图片的上传、压缩预览、定时删除。
如何用 JavaScript 制作一个好用又好玩的图片压缩工具
现在的设备发达了,图片拍下来动辄 5MB 10MB,单反相机歘欻欻一张经能达到 40MB,手机的内部储存也跟着很大,随便一个手机都 100G 。
独元殇
2023/03/21
9800
如何用 JavaScript 制作一个好用又好玩的图片压缩工具
移动商城第二篇(品牌管理模块)【文件上传、数据校验、CRUD】
添加品牌 在原型界面上,我们都是一些“死”数据,我们需要将数据库的记录代替这些“死”数据! 这里写图片描述 上传图片 服务端console对图片进行上传到我们的图片服务器上,而portal则访问的时候
Java3y
2018/04/02
1.6K0
移动商城第二篇(品牌管理模块)【文件上传、数据校验、CRUD】
Vue 图片压缩并上传至服务器
本文主要讲解基于 Vue + Vant ,实现移动端图片选择,并用 Canvas 压缩图片,最后上传至服务器。还会封装一个工具类,方便直接调用。
solocoder
2022/04/06
2.4K0
Vue 图片压缩并上传至服务器
推荐阅读
相关推荐
手把手教你实现一个图片压缩工具(Vue与Node的完美配合)
更多 >
LV.0
这个人很懒,什么都没有留下~
目录
  • 学习service worker 基本概念
    • 简介
      • Service workers
      • Promise
    • service worker准备工作
    • 注册service worker
      • 如何注册
      • 程序如何运行
      • 卸载service worker
    • 注册service worker的详细信息
      • 注册详情
      • 程序如何运行
      • 其他
    • 调试
      • 怎么做
    • 发生错误时提供稳定版本
    • 创建mock响应
    • 处理请求超时
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档