event-worker

1.3.3 • Public • Published

event-worker

Minimalistic event/promified driven web worker abstraction.

Build Status npm version JavaScript Style Guide

Install

npm

npm install event-worker --save

CDN

https://cdn.jsdelivr.net/npm/event-worker@1.3.0/index.min.js

Usage

Basic example

In your main thread (main.js):

const EventWorker = require('event-worker')
 
const worker = new EventWorker('path/to/my/worker.js')
 
async function test(){
  const user = await worker.emit('getUserById', { id: '30242' })
 
  /*
  {
    id: '30242',
    name: 'neil',
    lastname: 'tyson degrasse'
  }
  */
//...
 

And then in your web worker (worker.js) you can listen for that event and respond back with the requested data:

const EventWorker = require('event-worker')
 
const worker = new EventWorker()
 
worker.on('getUserById', async ({payload}) => {
 
  let user = await getUser(payload.id)
 
  return user // Respond back to the main thread with the data requested.
 
})
 
 
async function getUser(id){
 
  let user = await fetchUserFromLocalDatabase(id)
 
  if(user) return user
 
  user = await fetchUserFromServer(id)
 
  saveUserInLocaDatabase(user)
 
  return user
}

Workload splitting

If you want to keep your main thread running smoothly dividing the work load of expensive computational task between multiple web workers becomes easier.

From main thread (main.js):

const EventWorker = require('event-worker')
 
const workerPath = 'path/to/my/worker.js'
 
const workerPool = [
  new EventWorker(workerPath),
  new EventWorker(workerPath),
  new EventWorker(workerPath)
]
 
const sum = (a, b) => a + b
 
const multiplyBy2InOtherThread = (worker, index) => worker.emit('multiply_by_2', index)
 
(async ()=>
  (await Promise.all(
    workerPool.map(multiplyBy2InOtherThread)
  )).reduce(sum, 0)
)() // 6
 

From worker (worker.js):

 
importScripts('path/to/source/event-worker.js')
 
const worker = new EventWorker()
 
worker.on('multiply_by_2', ({payload}) => payload * 2 )
 

Bidirectional communication

You can listen for events triggered by your workers.

From main thread (main.js):

//...
 
worker.on('interestingData', ({payload})=>{
 
  doSomethingWithInterestingData(payload)
 
  return 'Good job worker!'
 
})
 
//..

From worker (worker.js):

 
//...
const res = await worker.emit('interestingData', 'interestingString')
 
res // => 'Good job worker!!'
 

Inlining code

Instead of having a separate file for your worker, you can wrap your code inside a function and pass it as an argument to the constructor of EventWorker. This is a good option when prototyping.

From main (main.js):

 
const worker = new EventWorker(async (mainThread) => {
 
  let res = await mainThread.emit('sayingHiFromWorker', 'Hi main thread!')
 
  console.log(res) // Hello worker!
 
})
 
worker.on('sayingHiFromWorker', ({payload}) => {
 
  console.log(payload) // Hi main thread!
 
  return "Hello worker!"
 
})

Caveat

When you inline functions it is easy to get confused by the execution context. If you try to access a variable that is outside the scope of the inline function it will fail.

 
const favoriteAnimal = 'chiguire'
 
const worker = new EventWorker(async (mainThread) => {
  // This will get executed in a worker.
  mainThread.on('onGetAnimals', ()=>{
 
    console.log(favoriteAnimal) // fails. favoriteAnimal variable is not in the same execution context.
 
    //...
  })
 
})
 

Error Handling

Error handling works the same as you would expect from a promise executed in the same thread:

From main thread (main.js):

const EventWorker = require('event-worker')
 
const worker = new EventWorker('path/to/my/worker.js')
 
worker.emit('rejectThisCall')
  .catch((reason) => {
    console.log(`Rejected because: "${reason}`)
  })
 

From worker (worker.js):

 
importScripts('path/to/source/event-worker.js')
 
const worker = new EventWorker()
 
//throwing errors
worker.on('rejectThisCall', () => {
  throw new Error()
})
 
// throwing async errors
worker.on('rejectThisCallAsync', async ()=> {
  throw new Error()
})
 

Instead of embedding event-worker into your worker file with a module bundler, you can use the built in function importScripts:

 
importScripts('path/to/source/event-worker.js')
 
const worker = new EventWorker()
 
// ...

EventWorker reference is injected into the global scope once it's loaded.

API

new EventWorker(source) EventWorker

Creates a new instance

  • source string | function | undefined

    • If a string is passed: It will assume it is the worker source file path.

    • If a function is passed it will get converted into a string an then transformed into a worker.

    • If nothing (undefined) is passed it will assume that the environment is the worker.

emit(eventName, data) Promise

Emits a event.

  • eventName String

  • data Any

on(eventName, callback) EventWorker

Registers for an event.

  • eventName

  • callback function(object) => Promise<any>

    Gets executed when eventName is emited.

    • object
      • object.payload any

        Data sent from the event emitter to the listener.

terminate() void

Immediately terminates the Worker. This does not offer the worker an opportunity to finish its operations; it is simply stopped at once.

Changelog

2017-11-04

  • Removed "resolve" and "reject" function properties in the "on" callback.

Contributing

All contributions are welcome.

License

MIT © Alvaro Bernal

Dependents (0)

Package Sidebar

Install

npm i event-worker

Weekly Downloads

2

Version

1.3.3

License

M.I.T

Unpacked Size

12.2 kB

Total Files

4

Last publish

Collaborators

  • alvarob