https://github.com/MetaMask/sw-controller
Service Worker Controller
Used to register a service worker and listen for a ready event. Can be used with sw-stream for easy plumbing.
这个模块是用来登录一个service worker并监听准备好的事件。可以与sw-stream结合使用
Usage
const SwController = require('sw-controller') const createSwStream = require('sw-stream') const controller = new SwController({ fileName: '/service-worker.js', // optional, scope used when registering service worker scope: '/', // default: true, pings the service worker to keep it alive keepAlive: true, }) controller.once('ready', () => { const swStream = createSwStream({ serviceWorker: controller.getWorker(), }) // talk to the service worker }) controller.startWorker()
sw-controller/lib/index.js
const EventEmitter = require('events') module.exports = class ClientSideServiceWorker extends EventEmitter { constructor (opts) { super() // opts this.fileName = opts.fileName this.scope = opts.scope this.keepAlive = opts.keepAlive === undefined ? true : opts.keepAlive // service worker refs this.serviceWorkerApi = navigator.serviceWorker this.activeServiceWorker = null // ready status this.ready = false this.once('ready', () => this.ready = true) // keep alive this.keepAliveActive = false this.keepAliveInterval = opts.keepAliveInterval || 60000 this.keepAliveIntervalRef = null this.keepAliveDelay = opts.keepAliveDelay || 0 if (this.keepAlive) { this.once('ready', () => this.startKeepAlive()) } // start if (opts.autoStart) this.startWorker() } getWorker() { return this.activeServiceWorker || this.serviceWorkerApi.controller } async startWorker () { const registeredWorker = await this.registerWorker() // forward messages and errors this.serviceWorkerApi.addEventListener('message', (messageEvent) => this.emit('message', messageEvent)) this.serviceWorkerApi.addEventListener('error', (err) => this.emit('error', err)) const swReady = await this.serviceWorkerApi.ready this.activeServiceWorker = swReady.active this.activeServiceWorker.onerror = (err) => this.emit('error', err) this.emit('ready', this.activeServiceWorker) } async registerWorker () { const registeredWorker = await this.serviceWorkerApi.register(this.fileName, { scope: this.scope }) registeredWorker.onupdatefound = (event) => { this.emit('updatefound') registeredWorker.update() } return registeredWorker } sendMessage (message) { return new Promise((resolve, reject) => { const messageChannel = new MessageChannel() messageChannel.port1.onmessage = (event) => { if (event.data.err) { reject(event.data.error) } else { resolve(event.data.data) } } this.getWorker().postMessage(message, [messageChannel.port2]) }) } startKeepAlive () { if (this.keepAliveActive) return this.keepAliveActive = true setTimeout(() => { this.keepAliveIntervalRef = setInterval(() => { this.emit('sendingWakeUp') this.sendMessage('wakeup') }, this.keepAliveInterval) }, this.keepAliveDelay) } stopKeepAlive () { if (!this.keepAliveActive) return clearInterval(this.keepAliveIntervalRef) this.keepAliveIntervalRef = null this.keepAliveActive = false } }