PWA离线优先策略:提升用户体验的关键步骤

Progressive Web Apps (PWA) 的离线优先策略是通过Service Worker和Cache API实现的,它允许在没有网络连接时仍然可以访问网站的部分或全部内容。

2500G计算机入门到高级架构师开发资料超级大礼包免费送!

1. 创建Service Worker注册文件(service-worker.js):

self.addEventListener('install', (event) => {event.waitUntil(caches.open('my-cache-v1').then((cache) => {return cache.addAll(['/index.html','/style.css','/script.js',// 添加其他需要预缓存的文件路径]);}));
});self.addEventListener('fetch', (event) => {event.respondWith(caches.match(event.request).then((response) => {if (response) {return response;}return fetch(event.request).then((networkResponse) => {caches.open('my-cache-v1').then((cache) => {cache.put(event.request.url, networkResponse.clone());});return networkResponse;}).catch(() => {// 如果所有尝试都失败,可以返回一个备用响应,比如错误页面return caches.match('/offline.html');});}));
});

2. 注册Service Worker:

在你的主应用中注册Service Worker:

if ('serviceWorker' in navigator) {window.addEventListener('load', () => {navigator.serviceWorker.register('/service-worker.js').then((registration) => {console.log('Service Worker registered:', registration);}).catch((error) => {console.error('Service Worker registration failed:', error);});});
}

3. 更新策略:

当有新版本的应用时,需要更新Service Worker和缓存内容。可以在Service Worker中监听activate事件:

self.addEventListener('activate', (event) => {event.waitUntil(caches.keys().then((cacheNames) => {return Promise.all(cacheNames.filter((cacheName) => cacheName !== 'my-cache-v1').map((cacheName) => caches.delete(cacheName)));}));
});

4. 更新Service Worker:

更新Service Worker时,需要改变Service Worker文件名(如增加版本号),这样浏览器会认为这是新的SW并触发安装过程。

5. 更新Service Worker生命周期管理:

确保在Service Worker更新时,旧版本的Service Worker不会影响用户体验。通常,你可能希望旧版本Service Worker完成所有请求后再关闭:

self.addEventListener('message', (event) => {if (event.data && event.data.type === 'SKIP_WAITING') {self.skipWaiting();}
});

6. 配置manifest文件:

创建一个manifest.json文件,定义应用的元数据和离线图标:

{"short_name": "My App","name": "My Awesome Progressive Web App","icons": [{"src": "icon-192.png","sizes": "192x192","type": "image/png"},{"src": "icon-512.png","sizes": "512x512","type": "image/png"}],"start_url": "/index.html","display": "standalone","background_color": "#ffffff","theme_color": "#000000"
}

在HTML中引用manifest文件:

<link rel="manifest" href="/manifest.json">

7. 离线通知和重新加载提示

当用户离线后重新上线时,可以通过Service Worker发送通知提醒用户重新加载页面以获取更新内容:

self.addEventListener('online', (event) => {clients.matchAll({ type: 'window' }).then((clients) => {clients.forEach((client) => {client.postMessage({ type: 'RELOAD' });});});
});self.addEventListener('message', (event) => {if (event.data && event.data.type === 'RELOAD') {clients.matchAll({ type: 'window' }).then((clients) => {clients.forEach((client) => {if (client.url === self.registration.scope && 'focus' in client) {client.focus();client.reload();}});});}
});

在主应用中监听消息:

navigator.serviceWorker.addEventListener('message', (event) => {if (event.data && event.data.type === 'RELOAD') {alert('网络已恢复,刷新页面获取最新内容。');location.reload();}
});

8. 离线提示和体验

当用户离线时,提供友好的离线页面或提示:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>离线页面</title><style>body {display: flex;justify-content: center;align-items: center;height: 100vh;margin: 0;background-color: #f2f2f2;}h1 {font-size: 2rem;color: #333;}</style>
</head>
<body><h1>您已离线,稍后再试。</h1>
</body>
</html>

然后在Service Workerfetch事件中处理:

self.addEventListener('fetch', (event) => {event.respondWith(caches.match(event.request).then((response) => {if (response) {return response;}// 检查网络请求失败的情况return fetch(event.request).catch(() => {// 返回离线页面return caches.match('/offline.html');});}));
});

9. 更新缓存策略

有时你可能希望缓存特定版本的资源,而不是始终使用最新的。这可以通过在Service Worker中添加版本控制来实现:

const CACHE_NAME = 'my-cache-v2';
const urlsToCache = [// ...
];self.addEventListener('install', (event) => {event.waitUntil(caches.open(CACHE_NAME).then((cache) => {return cache.addAll(urlsToCache);}));
});self.addEventListener('fetch', (event) => {event.respondWith(caches.match(event.request).then((response) => {if (response) {return response;}return fetch(event.request).then((networkResponse) => {caches.open(CACHE_NAME).then((cache) => {cache.put(event.request.url, networkResponse.clone());});return networkResponse;});}));
});

10. 使用App Shell架构

App Shell模型是一种常见的PWA设计模式,它提供一个基本的用户界面框架,即使在离线状态下也能加载。App Shell通常包括导航、头部、侧边栏等非动态内容,这样即使在离线时,用户也能看到应用的基本结构。

首先,创建一个App Shell HTML文件(如app-shell.html),包含基本的布局和样式。然后,在Service Worker中预缓存App Shell:

const appShellUrls = ['/app-shell.html','/app-style.css',// 其他App Shell相关的资源
];self.addEventListener('install', (event) => {event.waitUntil(caches.open('app-shell-cache').then((cache) => {return cache.addAll(appShellUrls);}));
});

fetch事件中,优先从缓存中获取App Shell资源:

self.addEventListener('fetch', (event) => {if (event.request.mode === 'navigate') {event.respondWith(caches.match('/app-shell.html'));} else {event.respondWith(caches.match(event.request).then((response) => {if (response) {return response;}return fetch(event.request);}));}
});

11. 使用Service Worker拦截网络请求

Service Worker还可以用于拦截特定类型的网络请求,例如API调用。这使得你可以在离线时返回默认值或存储的响应,以提供一致的用户体验:

self.addEventListener('fetch', (event) => {if (event.request.url.startsWith('https://api.example.com')) {event.respondWith(caches.match(event.request).then((response) => {if (response) {return response;}return fetch(event.request).then((networkResponse) => {caches.open('api-cache').then((cache) => {cache.put(event.request.url, networkResponse.clone());});return networkResponse;});}));} else {// 处理其他非API请求}
});

12. 集成WebSocket支持

如果你的应用使用WebSocket进行实时通信,可以使用workbox-websocket库在Service Worker中处理WebSocket连接,确保在离线时能够接收和发送消息:

importScripts('https://unpkg.com/workbox-sw@latest/runtime-caching/workbox-sw.prod.v2.js');
importScripts('https://unpkg.com/workbox-websocket@latest/workbox-websocket.prod.v2.js');workbox.webSocket.register('wss://your-websocket-endpoint.com', {onConnect: (client) => {console.log('WebSocket connected:', client);},onClose: (client) => {console.log('WebSocket disconnected:', client);},
});

13. 测试和监控

确保在不同网络条件下测试你的PWA,包括2G、3G和离线状态。可以使用Chrome开发者工具的模拟网络条件功能。同时,使用Lighthouse等工具定期评估PWA的性能和离线体验。

14. 总结

通过这些策略,可以创建一个高度可用且用户体验优秀的PWA,即使在离线或弱网络环境下也能正常工作。PWA的目标是提供接近原生应用的体验,因此持续优化和测试是关键。

2500G计算机入门到高级架构师开发资料超级大礼包免费送!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/14740.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从零开始学Vue3--模板语法

Vue的核心是MVVM,也就是数据能够影响界面&#xff0c;界面也能影响数据&#xff0c;什么意思呢&#xff1f;比如有个输入框&#xff0c;它绑定的变量name,如果你改变了name的值&#xff0c;输入框显示的值就会变化&#xff0c;如果用户在输入框里面输东西,name对应的值也会变化…

AI预测福彩3D采取888=3策略+杀断组+杀和尾缩水测试5月24日预测第1弹

哈喽&#xff0c;各位亲爱的小伙伴&#xff0c;在发布本期预测结果之前&#xff0c;先对最近的这套算法测试做一下总结。 最近的一套算法采用了88723的容差策略&#xff0c;关于容差策略相信大家都比较清楚&#xff1a;容差可以最大限度的保证初始大底中包含中奖号码&#xff0…

揭秘Python:对象类型打印

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 一、Python数据类型简介 在Python的世界中&#xff0c;了解你正在处理的数据类型是至关重要的。Python提供了多种内置数据类型&#xff0c;包括数字&#xff08;整数和浮点数&#xff09;、字符串、列表、元组、字典…

解决:error: failed to push some refs to ‘https://gitee.com/***/***.git‘(高效快速)

解决方案&#xff1a; git pull --rebase origin master 具体原因&#xff1a; 主要原因是gitee(github)中的README.md文件不在本地代码目录中 要执行git pull --rebase origin master命令将README.md拉到本地 然后就可以执行git push啦 写在最后&#xff1a; 要是问题得到…

服务开机自启

目录 1、启动脚本 1)新建sh脚本 2)日志备份 2、自启动Service 1)编写Service 1)含义: 3、调整启动脚本 1)替换start():

Leetcode 3152. Special Array II

Leetcode 3152. Special Array II 1. 解题思路2. 代码实现 题目链接&#xff1a;3152. Special Array II 1. 解题思路 这一题的话思路上就是分堆&#xff0c;使用贪婪算法找到每一个元素所在的最长special子序列&#xff0c;然后判断query的首尾元素是不是属于同一个special…

51-指针_野指针,指针运算

51-1 野指针 51-1-1 什么是野指针 概念&#xff1a;野指针就是指针指向的位置是不可知的&#xff08;随机的、不正确的、没有明确限制的) 没有初始化 int main() {int* p;//p没有初始化&#xff0c;就意味着没有明确的指向//一个局部变量不初始化的话&#xff0c;放的是随机…

MySQL 插入数据的时候自动忽略重复数据

MySQL中插入数据&#xff0c;如果插入的数据在表中已经存在&#xff08;主键或者唯一键已存在&#xff09;&#xff0c;使用insert into语法的时候&#xff0c;如果遇到重复数据&#xff0c;会直接报错&#xff0c;导致事务回滚&#xff0c;所有插入数据&#xff0c;全部失败。…

TCP/IP体系模型简介

一、TCP/IP 概念 TCP&#xff08;Transmission Control Protocol 传输控制协议&#xff09;&#xff1a; 是一种面向连接的、可靠的传输层协议。通过三次握手建立连接&#xff0c;确保连接的可靠建立。对数据进行有序传输&#xff0c;并具有确认机制和重传机制来保证数据的完整…

SpringBoot多数据源启动出现循环依赖问题

在使用SpringBoot的项目中&#xff0c;如果是有使用多数据源&#xff0c;可能会存在启动时数据源循环依赖的报错&#xff0c;是因为使用了多数据源注入&#xff0c;和DataSourceAutoConfiguration数据源自动配置的DataSourceInitializerInvoker互相产生循环依赖导致。 这种错误…

03-01-Vue组件的定义和注册

前言 我们接着上一篇文章02-Vue实例的生命周期函数 来讲。 下一篇文章 03-02-Vue组件之间的传值 什么是组件 组件&#xff1a; 组件的出现&#xff0c;就是为了拆分Vue实例的代码量的&#xff0c;能够让我们以不同的组件&#xff0c;来划分不同的功能模块&#xff0c;将来我们…

Java_网络编程

网络编程 定义&#xff1a; 网络编程就是计算机跟计算机之间通过网络进行数据传输 常见的软件架构&#xff1a; 1.C/S&#xff08;Client/Server&#xff09;&#xff1a;客户端/服务器模式 2.B/S&#xff08;Browser/Server&#xff09;&#xff1a;浏览器/服务器模式 区别…

安全系列---入门

目录 xss注入问题Authenticator认证器 xss注入问题 现象&#xff1a;前端显示内容非预期原因&#xff1a;反射型注入和存储型注入&#xff0c;本质都是利用输入框输入一段js代码。解决&#xff1a;利用html的转义解析&#xff0c;当浏览器遇到HTML转义符时&#xff0c;它会将其…

深入理解MySQL:查询表的历史操作记录

摘要&#xff1a;在数据库管理中&#xff0c;了解如何查询表的历史操作记录对于追踪数据变更、审计数据以及恢复误操作至关重要。本文将深入探讨MySQL中查询表的历史操作记录的方法&#xff0c;并提供多个实例以帮助读者更好地理解和应用这一技术。 引言 在数据库管理中&#…

Kivy.garden.NavigationDrawer

totally copied from github opensource code. Just a translation and ideas with idividuals ideas to share its use for all people using chinese. Copyright © 2013 Alexander Taylor 开源免责免费使用声明: #Permission is hereby granted, free of charge, to any…

【SpringBoot项目开发】查看购物车和清空购物车实现

查看和清空购物车的注意事项&#xff1a; 需要查看登录用户购物车中所有的信息&#xff0c;但是请求参数中可以不包含用户id&#xff0c;因为请求时会附带一个token&#xff0c;从token中能解析到用户id。 return shoppingCartMapper.list(ShoppingCart.builder().userId(Bas…

GQL图查询语言:高效处理复杂图数据

GQL是一种新型的查询语言&#xff0c;它可以处理复杂图数据&#xff0c;以提供比传统 SQL更快、更高效的查询方式。GQL图查询语言具有可扩展性&#xff0c;可以使用最少的编程知识来访问图数据库。在本文中&#xff0c;我们将探讨 GQL的概念和实际使用案例。同时&#xff0c;我…

C++: 多态

目录 一、多态的概念 二、多态的定义及实现 2.1虚函数 2.2虚函数的重写 2.3多态的构成条件 2.4虚函数重写的两个例外 1.协变 2.析构函数的重写 2.5虚函数重写的实质 2.6override 和 final&#xff08;C11&#xff09; 1.final 2.override 2.7重载、覆盖&#xff0…

go语言之变量

go是静态类型语言&#xff0c;因此变量是具有明确类型的&#xff0c;编译器也会检查变量类型的正确性 我们从计算机系统的角度来讲&#xff0c;变量就是一段或者多段内存&#xff0c;用于存储数据 文章目录 变量声明标准格式简便格式不指定变量类型批量声明简短格式 匿名变量变…

http协议报文头部结构解释

http协议报文头部结构 请求报文 报文解释 请求报文由三部分组成&#xff1a;开始行、首部行、实体主体 开始行&#xff1a;请求方法&#xff08;get、post&#xff09;url版本 CRLE 方法描述GET请求指定页面信息&#xff0c;并返回实体主体HEAD类似get要求&#xff0c;只不…