抛开AppCache,有一个新的API用于构建互动的、功能丰富的应用程序-Service Workers。Service Workers是在浏览器中与网页分开运行的JavaScript函数。它们允许长期运行的任务,如推送通知、后台同步,以及提供页面的缓存版本。它们旨在帮助网站创建者在网络连接有限或没有网络连接的情况下提供可用的网络应用版本。例如,考虑像Google Docs这样的网站。在Google Docs中,大部分的工作都发生在客户端。服务器只需要传输对文档的修改,但文档本身是在客户端工作的。有了Service Workers,像Google Docs这样的网站可以通过将变化缓存到本地浏览器队列中来更有效地离线工作。然后,当连接恢复时,这些变化将被送回谷歌的服务器并持久化。今天,83%的浏览器都支持Service Workers。不支持的浏览器包括Internet Explorer 11、Edge 16版及以前的版本、iOS 11.2版及以前的Safari和Opera Mini。一、关于Service Workers的重要特征Service workers具有以下特点:必须使用HTTPSService workers只能通过HTTPS提供。这是为了防止Service Workers在传输过程中被修改或替换。恶意的 Service Workers 可以劫持连接、拦截请求和响应、执行跨站脚本攻击或造成其他形式的损害。使用HTTPS确保 Service Workers 在服务器和你的浏览器之间没有被篡改过。无法访问DOMService Workers在一个独立的线程中运行,而他们的源头是网页。这使他们无法与文档对象模型(DOM)进行交互,因此他们无法读取或修改页面的内容。然而, Service Workers 可以使用postMessage与页面进行通信。暂时的和不可改变的Service Workers只在需要的时候运行,并不持久保存信息。这意味着你不能在Service Workers实例之间维护一个全局状态。相反,你可以通过使用IndexedDB API来持久化和重复使用信息。基础承诺Service Workers大量使用Promises。Service Workers必须是非阻塞的,因此不能使用同步的API,如localStorage。二、如何使用Service WorkersService Workers有许多不同的应用,包括缓存、向服务器推送和检索数据、转发消息以及支持网站的离线功能。你可以在Mozilla提供的ServiceWorker Cookbook中找到几个例子。作为一个例子,让我们创建一个显示图像的简单网站。我们将使用一个Service Workers来检查本地缓存中的图片副本,如果没有,就从其原始网站下载图片。1. 注册Service Workers在创建新的Service Workers时,您首先需要告诉浏览器它的位置。注册可以在另一个Service Workers、脚本或页面本身中进行。您可以根据 URL 为其指定一个范围,但默认情况下,其范围仅限于它所在的文件夹。例如,在”/js/worker.js “处注册Service Workers,对于任何URL以”/js/”开头的请求,都会启动该工作者。这个例子在页面加载时注册了工作者。# page.jsif ('serviceWorker' in navigator) { window.addEventListener('load', function() { navigator.serviceWorker.register('/worker.js').then(function(registration) { // Successful registration }, function(err) { // Unsuccessful registration }); });}安装成功后,Service Workers会等待以前版本的工作者完成后再启动。这是为了确保每次只有一个版本的Service Workers在运行。当旧的 Service Workers 消失,新的 Service Workers 启动时,会触发激活事件。这是删除旧工作者的功能、执行升级等的理想时间。2. 安装Service Workers注册Service Workers后,现在需要安装它。安装事件在Service Workers第一次被取走时运行。这可以让您在 Service Workers 实际运行之前对其进行初始化。继续我们之前的例子,我们将在我们的Service Workers文件中添加一个安装方法,将图像下载到缓存中。# worker.jsself.addEventListener('install', function(event) { event.waitUntil( caches.open('site-cache') .then(function(cache) { return cache.add(image.png); }) );});3. 定义获取事件现在工作者已经安装完毕,您需要定义每次有请求从Service Workers的范围内发出时的情况。这些请求由 fetch 事件来处理。换句话说,由”/subfolder “URL 中的页面或脚本触发的任何请求都将通过该方法。# worker.jsself.addEventListener('fetch', function(event) { event.respondWith( caches.match(event.request) .then(function(response) { if (response) { // Cache hit return response; } // Cache miss: pass request to server return fetch(event.request); }) );});三、为Service Workers制定基准由于其多功能性,Service Workers的真正性能优势取决于其应用。就我们的目的而言,我们将测试Service Workers的缓存性能与浏览器内的缓存相比。为了进行测试,我们创建了两个网站。两个网站都显示相同的内容,但其中一个使用Service Workers来缓存每个页面的内容。我们将每个网站部署到运行Nginx 1.10.3的f1-micro Google Compute Engine实例上。我们使用默认的Nginx设置,除了启用TLS 1.2,因为Service Workers需要HTTP。对于网站的内容,我们创建了一个简单的HTML文档,显示来自NASA图片库的以下图片。Image 1Image 2Image 3我们使用Sitespeed.io 7.2.0版本来收集性能统计数据。我们在每次测试前使用-preURL参数来预热缓存。对于以下每个指标,我们显示了Sitespeed.io计算的平均值(以毫秒为单位)。FirstPaint:直到浏览器首次开始渲染页面的时间。BackEndTime:服务器生成并开始发送HTML所需的时间。ServerResponseTime:服务器发送响应所需的时间。最后一次视觉变化:浏览器中最后一次视觉变化的时间。我们用它来代替PageLoadTime,以便更好地跟踪总的图像加载时间。不含Service Workers对于基本的网页,我们使用基本的HTML 标签来显示页面上的每张图片。MetricTest 1Test 2Test 3AverageFirstPaint128134119127BackEndTime46464746ServerResponseTime46484948Last Visual Change2267246723672367含有Service Workers对于启用了Service Workers的网页,我们用一个 JavaScript 函数取代了 标记,该函数获取了图片并将其插入到页面的主体中。我们在部分注册了Service Workers,以确保任何请求都被Service Workers拦截。MetricTest 1Test 2Test 3AverageFirstPaint741747731740BackEndTime51515251ServerResponseTime64526460Last Visual Change1900186718331867启用Service Workers后,第一字节的时间要长得多(由FirstPaint表示),但页面加载时间总体上减少了500ms。这可能是由于Service Workers在开始渲染页面之前拦截并检查每个请求。由于所有繁重的工作都发生在浏览器中,因此后端和服务器响应时间的差异很小。显然,Service Workers的速度很快,即使与浏览器内的缓存相比也是如此。四、总结Service Workers是非常通用的技术,对现代网站来说有很大的潜力。除了简单的缓存机制,Service Workers还可以帮助进一步缩小桌面和网络应用之间的差距。
THE END