MST

星途 面试题库

面试题:JavaScript中Service Worker与多页面应用离线协同问题

在一个复杂的JavaScript多页面应用中使用Service Worker实现离线访问,如何确保不同页面间的缓存一致性和更新的平滑过渡,以及如何处理跨域资源在离线状态下的正常加载和使用。
20.4万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

确保不同页面间的缓存一致性和更新的平滑过渡

  1. 缓存策略
    • 使用统一的缓存名称和版本
      • 在Service Worker中,为所有缓存资源定义一个统一的缓存名称,比如myAppCache - v1。当需要更新缓存时,只需要更改版本号,如myAppCache - v2。这样,不同页面都会基于相同的缓存策略进行缓存操作。
      • 示例代码:
const CACHE_NAME ='myAppCache - v1';
self.addEventListener('install', function (event) {
    event.waitUntil(
        caches.open(CACHE_NAME)
          .then(function (cache) {
                return cache.addAll([
                    // 列出需要缓存的资源路径
                    '/index.html',
                    '/styles.css',
                    '/scripts.js'
                ]);
            })
    );
});
  • 原子更新
    • 在更新缓存时,采用原子更新的方式。即先创建一个新的缓存版本,将新的资源缓存到新的版本中,然后在更新完成后,删除旧的缓存版本。这样可以避免在更新过程中不同页面访问到不一致的缓存状态。
    • 示例代码:
self.addEventListener('activate', function (event) {
    event.waitUntil(
        caches.keys().then(function (cacheNames) {
            return Promise.all(
                cacheNames.filter(function (cacheName) {
                    return cacheName.startsWith('myAppCache - ') && cacheName!== CACHE_NAME;
                }).map(function (cacheName) {
                    return caches.delete(cacheName);
                })
            );
        })
    );
});
  1. 推送更新通知
    • 当Service Worker检测到有新的更新时,可以通过postMessage等方式向页面发送更新通知。页面接收到通知后,可以提示用户有新的更新,用户确认后,通过刷新页面来获取新的缓存内容。
    • 示例代码(Service Worker部分):
self.addEventListener('message', function (event) {
    if (event.data === 'check - for - update') {
        self.registration.update().then(function () {
            event.source.postMessage('update - available');
        });
    }
});
  • 示例代码(页面部分):
if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/service - worker.js')
      .then(function (registration) {
            registration.serviceWorker.postMessage('check - for - update');
            window.addEventListener('message', function (event) {
                if (event.data === 'update - available') {
                    if (confirm('有新的更新,是否刷新页面?')) {
                        location.reload();
                    }
                }
            });
        });
}

处理跨域资源在离线状态下的正常加载和使用

  1. CORS配置
    • 在服务器端配置CORS(跨域资源共享),允许Service Worker所在的源访问跨域资源。例如,在Node.js中使用cors中间件:
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
// 其他路由和服务器配置
  1. 代理模式
    • 在Service Worker中,可以通过代理模式来处理跨域资源。即Service Worker拦截跨域请求,将请求转发到自己的服务器,服务器再去请求跨域资源,并将响应返回给Service Worker,Service Worker最后将响应返回给页面。
    • 示例代码:
self.addEventListener('fetch', function (event) {
    if (event.request.url.startsWith('跨域资源的域名')) {
        event.respondWith(
            fetch('/proxy?url=' + encodeURIComponent(event.request.url))
        );
    }
});
  • 在服务器端(假设是Node.js),实现代理逻辑:
const http = require('http');
const url = require('url');
http.createServer(function (req, res) {
    if (req.url.startsWith('/proxy')) {
        const query = url.parse(req.url, true).query;
        const targetUrl = decodeURIComponent(query.url);
        http.get(targetUrl, function (proxyRes) {
            proxyRes.pipe(res);
        });
    }
}).listen(8080);
  1. 预缓存跨域资源
    • 如果跨域资源相对稳定,可以在Service Worker的install事件中预缓存这些跨域资源。但要注意,这种方式可能需要服务器端允许跨域访问,并且可能会因为资源更新不及时导致缓存内容陈旧。
    • 示例代码:
self.addEventListener('install', function (event) {
    event.waitUntil(
        caches.open(CACHE_NAME)
          .then(function (cache) {
                return cache.addAll([
                    // 跨域资源路径
                    'https://example.com/cross - origin - script.js'
                ]);
            })
    );
});