前言
现在的网站不再是单纯的信息展示平台,越来越多的应用功能需要在 web 端实现。但是 web 应用有一个很大的问题,就是不可靠的网络环境。当网络连接不稳定或者处于离线状态时,大部分的应用都无法继续执行,用户也无法正常使用应用。这时候,PWA 就起到了作用。
PWA(Progressive Web App)是一个 Web 应用的技术概念,它涉及到多个方面的特点和技术,比如缓存、离线使用、推送通知等等。其中,离线使用是 PWA 最核心的特性之一。离线使用要解决的一个关键问题就是数据持久化问题,因为离线时无法从服务器获取数据,需要从客户端本地存储获取数据。而 IndexedDB 就是一种客户端存储数据的解决方案。
本篇文章将详细介绍 PWA 技术中的离线使用特性,重点讲解如何利用 IndexedDB 解决客户端数据持久化问题。
PWA 技术中的离线使用特性
PWA 的离线使用并不是指完全离线,而是指在网络连接不可靠的情况下,用户仍然能够使用应用,同时也能在线时提供更好的用户体验。离线使用特性包括应用缓存、Service Worker 等。
应用缓存
应用缓存是 PWA 技术中用于离线使用的一种传统技术。应用缓存机制使得 Web 应用可以将资源缓存到客户端,当用户离线时,可以从缓存读取资源而不是从网络加载。应用缓存需要在 HTML 的头部添加 manifest 文件,注意要勾选 manifest 文件 MIME 类型支持。
// javascriptcn.com 代码示例 <!DOCTYPE html> <html manifest="http://example.com/cache.manifest"> <head> <title>Example</title> ... </head> <body> ... </body> </html>
在 cache.manifest 文件中定义需要缓存的资源:
CACHE MANIFEST # v1 2022-01-01 /index.html /main.css /main.js
应用缓存机制有如下缺点:
- 应用缓存机制在应用首次加载时,需要下载 cache.manifest 文件和缓存资源,而且如果 cache.manifest 文件没有更新,则浏览器会始终使用缓存,难以更新。
- 应用缓存机制只能缓存静态资源,对于动态页面和数据,无法灵活处理,也没有处理机制。
Service Worker
Service Worker 是 PWA 技术中比较新颖的离线使用方案,它是一个 JavaScript 工作线程,用于拦截和响应网络请求。通过 Service Worker,可以离线缓存页面、响应网络请求、推送通知等等。
Service Worker 是一个独立的进程,可以在后台运行,不需要与页面交互,可以直接与服务器进行通信。通过 Service Worker,可以将网络请求拦截到客户端,可以在离线时使用缓存资源,也可以在在线环境下将资源异步存储到缓存中。
Service Worker 的使用步骤如下:
- 注册 Service Worker
通过注册 Service Worker,浏览器将 Service Worker 载入到浏览器,并将其加入到 Service Worker 控制范围。
// javascriptcn.com 代码示例 if ('serviceWorker' in navigator) { window.addEventListener('load', function() { navigator.serviceWorker.register('/sw.js').then(function(registration) { console.log('ServiceWorker registration successful with scope: ', registration.scope); }, function(err) { console.error('ServiceWorker registration failed: ', err); }); }); }
- 编写 Service Worker 脚本
Service Worker 脚本需要通过 self.addEventListener() 注册事件,以响应浏览器发送的事件,比如安装、激活、错误等事件。
// javascriptcn.com 代码示例 self.addEventListener('install', function(event) { event.waitUntil( caches.open('v1').then(function(cache) { return cache.addAll([ '/index.html', '/styles/main.css', '/scripts/main.js', '/images/logo.png' ]); }) ); }); self.addEventListener('fetch', function(event) { event.respondWith( caches.match(event.request).then(function(response) { return response || fetch(event.request); }) ); });
- 缓存需要离线使用的资源
Service Worker 脚本中可以通过 caches.open() 打开或创建一个缓存空间,并通过 cache.addAll() 将需要离线使用的资源添加到缓存。
- 拦截网络请求并响应缓存数据
通过在 Service Worker 中注册 fetch 事件,可以拦截浏览器的网络请求,并响应缓存数据。如果缓存中没有资源,则通过 fetch() 获取后缓存。
利用 IndexedDB 解决客户端数据持久化问题
客户端数据持久化是 PWA 离线使用特性的核心之一。为了更好地支持客户端数据持久化,HTML5 引入了 IndexedDB API。
IndexedDB 是一个基于键值对存储的数据库,提供了用于客户端数据存储和检索的 API。利用 IndexedDB,可以将数据存储到客户端本地,以供后续使用,实现客户端数据持久化。
以下是 IndexedDB 的使用步骤:
- 打开或创建数据库
// javascriptcn.com 代码示例 const request = indexedDB.open('myDatabase', 1); request.onerror = function(event) { console.log('Database error: ' + event.target.error); }; request.onupgradeneeded = function(event) { const db = event.target.result; const store = db.createObjectStore('customers', { keyPath: 'id' }); store.put({ id: 1, name: 'John Doe' }); }; request.onsuccess = function(event) { const db = event.target.result; const transaction = db.transaction('customers', 'readonly'); const store = transaction.objectStore('customers'); const request = store.get(1); request.onsuccess = function(event) { console.log(request.result); }; };
首先,要打开或创建一个 IndexedDB 数据库。在打开数据库时,需要指定数据库名称和版本号。如果数据库不存在,则自动创建一个空数据库。如果指定的版本号高于已存在的版本号,则触发 onupgradeneeded 事件,执行数据库升级逻辑。
- 创建对象存储空间
在数据库打开成功时,需要创建一个对象存储空间,以存储数据。在创建对象存储空间成功后,可以将数据存储到对象存储空间中,可以直接使用 put() 方法存储数据。
- 执行事务操作
使用 IndexedDB 进行数据存储和检索时,需要使用事务来控制操作序列。事务可以实现对数据的隔离性和原子性控制,可以保证数据的一致性。
在事务内部,使用 objectStore() 方法获取对象存储空间,通过 get() 或者 getAll() 方法获取数据。获取到数据后,可以进行更新或删除等操作。
总结
PWA 的离线使用特性是 Web 应用实现离线使用的重要手段,其中客户端数据持久化是离线使用的核心,可以通过 IndexedDB 实现客户端数据的存储和检索。IndexedDB 提供了用于客户端数据存储和检索的 API,可以实现客户端数据持久化,提高应用的可靠性和体验。
随着 Web 应用的普及,PWA 技术将越来越受到关注和重视,相信未来 Web 技术将取得更大的进步和发展。
参考资料
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/652f4c997d4982a6eb064df6