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 ||
this.keepAliveIntervalRef = null
this.keepAliveDelay = opts.keepAliveDelay ||
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
}
}