前言
近年来,PWA(Progressive Web Application)成为了前端开发的新热点,PWA 的出现极大的提升了 Web 应用的用户体验。其中,Service Worker(以下简称 SW)作为 PWA 技术的核心之一,在提供了离线访问的能力的同时,还可以优化页面的性能。本文将介绍如何利用 SW 实现图片懒加载,优化页面加载速度和用户体验。
图片懒加载
图片懒加载是一种常用的优化网页性能的技术,它可以将不在可视范围内的图片延迟加载,直到用户需要时才加载。这样做的好处是可以缩短页面的加载时间,减少用户流量消耗,提高用户体验。下面是一个简单的图片懒加载的实现:
// javascriptcn.com 代码示例 // 获取所有需要懒加载的图片 const lazyImages = document.querySelectorAll('img[data-src]'); // 计算当前可视区域的位置 function isEnterView(el) { const rect = el.getBoundingClientRect(); return rect.top < window.innerHeight && rect.bottom > 0; } // 加载所有在可视区域内的图片 function loadVisibleImages() { lazyImages.forEach(img => { if (isEnterView(img)) { img.src = img.dataset.src; img.removeAttribute('data-src'); } }); } // 监听窗口滚动事件,加载可视区域内的图片 window.addEventListener('scroll', loadVisibleImages); // 页面加载时,立即加载可视区域内的图片 document.addEventListener('DOMContentLoaded', loadVisibleImages);
这段代码定义了一个 lazyImages
包含了所有需要懒加载的图片,通过 isEnterView
函数判断一个图片是否在可视范围内,然后在页面滚动的时候调用 loadVisibleImages
函数将可视区域内的图片加载出来。
然而,当我们在使用 PWA 技术时,这种做法会遇到一些问题。
PWA 中的问题
当页面安装为 PWA 之后,每次用户打开页面时,浏览器会主动从缓存中获取资源,而不是从服务器端获取。这样做的好处是可以极大地提高页面加载速度,减少客户端与服务器的通讯。但是,对于需要懒加载的图片,这种做法会造成一些问题。
当页面第一次安装为 PWA 时,用户并没有滚动到可视区域内的图片,这些图片将不会被加载。即使用户之后滚动到了这个位置,浏览器也不会主动加载图片,因为它已经从缓存中获取了所有的资源。
这个问题会给用户带来一些不必要的麻烦。当用户第一次打开这个页面时,由于一些图片还没有被加载,用户可能会看到空白的空间,影响了页面的美观程度。当用户滚动到这些位置时,图片也不会立即加载,用户需要等待一段时间才能看到图片,影响了用户体验。为了解决这个问题,我们需要将图片的加载方式改为使用 SW。
利用 SW 实现图片懒加载
在使用 SW 时,我们可以通过缓存策略来控制图片的加载过程。具体来说,当用户请求某个图片时,我们可以让 SW 先从缓存中查找该资源,如果缓存中没有该资源,则从网络中获取该资源并存储到缓存中。做到这一点的关键是利用 SW 中的 fetch 事件和 cache API。
下面是一个通过 SW 实现图片懒加载的示例代码:
// javascriptcn.com 代码示例 // 定义缓存名称 const CACHE_NAME = 'lazy-load-cache'; // 监听 fetch 事件,实现缓存策略 self.addEventListener('fetch', event => { const { request } = event; const url = new URL(request.url); // 如果请求的是需要懒加载的图片 if (url.pathname.match(/\.(jpg|png|gif)$/)) { event.respondWith(loadImage(request)); } }); async function loadImage(request) { const cache = await caches.open(CACHE_NAME); const cachedResponse = await cache.match(request); if (cachedResponse) { // 如果缓存中已经有该图片,则直接返回缓存中的图片 return cachedResponse; } else { // 如果缓存中没有该图片,则从网络中获取 const response = await fetch(request); cache.put(request, response.clone()); return response; } }
这段代码通过监听 SW 中的 fetch 事件,实现了一个简单的缓存策略。当页面请求某个资源时,会先检查缓存中是否有该资源,如果有,则返回缓存中的资源,否则从网络中获取该资源并存储到缓存中。
现在我们可以将图片的加载方式改为使用 SW,将需要懒加载的图片的 src 属性设置为一个占位符,然后在图片进入可视范围内时,将其 src 属性替换为实际的图片地址,这样就可以避免上文所述的问题了。下面是修改后的代码:
<img data-src="/path/to/real/image.jpg" src="/path/to/placeholder.png">
// javascriptcn.com 代码示例 // 将所有需要懒加载的图片设置为占位符 const lazyImages = document.querySelectorAll('img[data-src]'); lazyImages.forEach(img => { img.src = '/path/to/placeholder.png'; }); // 监听窗口滚动事件,加载可视区域内的图片 function loadVisibleImages() { lazyImages.forEach(img => { if (isEnterView(img)) { loadImage(img); lazyImages.filter(el => el === img).pop(); } }); } // 定义 loadImage 函数,通过 SW 加载图片 function loadImage(img) { const url = new URL(img.dataset.src, location.origin); fetch(url, { mode: 'no-cors' }) .then(response => response.blob()) .then(blob => { img.src = URL.createObjectURL(blob); delete img.dataset.src; }); }
这段代码首先将所有需要懒加载的图片设置为占位符,然后在滚动事件中调用 loadImage
函数将可视区域内的图片加载出来,loadImage
函数通过 SW 加载图片,并将资源的 URL 转换为 blob
URL,然后将其设置为图片的 src
属性。为了保持代码的简洁性,本示例并没有考虑图片加载失败、SW 更新等异常情况,实际应用中需要根据具体情况进行处理。
总结
本文介绍了如何利用 SW 实现图片懒加载,并解决了在 PWA 中可能存在的图片加载问题。通过这种方式,可以提高页面的加载速度和用户体验,同时也充分利用了 PWA 技术的优势。值得注意的是,由于 SW 需要使用 HTTPS 协议才能生效,因此要确保在使用 SW 时,页面已部署到了 HTTPS 环境下。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/652f57e37d4982a6eb07559c