MetaMask/sw-controller

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
  }
}

 

 
posted @ 2018-11-07 16:51  慢行厚积  阅读(282)  评论(0编辑  收藏  举报