quicker-worker

0.1.0 • Public • Published

Quicker Worker

A library for quickly using web worker in browser. It is not designed for node side, just for browser side.

Install

npm install quicker-worker

or

<script src="dist/quicker-worker.js"></script>

Usage

If you use module import:

import {create, run} from 'quicker-worker'

let $worker = create(`function(n) {
  n ++
  return n
}`)

$worker.invoke(12).todo(n => {
  console.log(n)
  worker.close()
})

If you use global link:

let create = window.QuickerWorker.create
let run = window.QuickerWorker.run

Only two functions create and run provided. So it is easy to use.

API

Now let's talk about these two functions.

create(factory)

This function create a worker instance. So after you created an instance, you will use it for more operation.

let $worker = create(`function(p1, p2) {
  // ...
}`)

factory

The function to run in worker thread when you invoke. It should better to be a sting, which is like a function. However, you can directly pass a function if you have not special variables in it (a function will be transformed to be a string when concated with a string). So the following two are both ok:

Use string:

let $worker = create(`function(p1, p2) {
  // ... you can use $xhr here if you set `xhr` in `options` to be true
}`)

Use function:

let $worker = create(function(p1, p2) {
  // ... don't use $xhr here
})

And you'd better to know that, program in worker thread use the different memory context, so your main js thread is not sharing variables with worker thread. So, do not using variables which is in main js script in factory function. One word, treat factory function as a single scope.

And you should know more about web worker program: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers.

$worker

An instance will be created after you use create. Let's call it $worker. So $worker will have 2 special properties more than a normal worker instance: invoke, close.

$worker.invoke(data).todo(data => {}).catch(e => {})

Use this to run the factory you have passed into create. Every time you run invoke, the factory will be run once.

data:

It is params passed into factory. For example:

let $worker = create(`function(p1, p2) {
  return $xhr.post('your_url', {p1, p2})
}`)
$worker.invoke(['name', 'age']).todo(data => {
  console.log(data)
})

You give p1 and p2 as params of factory, and when you run invoke, you should pass an array which will be used as fn.apply's second parameter.

If your factory has only one parameter, you can just pass one data, not need to pass an array:

let $worker = create(`function(data) {
  return $xhr.post('your_url', data)
}`)
$worker.invoke({name: 'tom'}).todo(data => {
  console.log(data)
})

I mentioned $xhr in previous code. $xhr and $notify is available in your factory program. I will talk about them later.

return value in factory:

You should return a value or a promise in factory. If you do not return anything, todo will recieve nothing. However, if you use $notify in factory, it is ok to return nothing, $notify data will be recieved by todo.

After you run invoke, the factory function will be run, and the return value or promise or $notify data will be passed into todo:

let $worker = create(`function(data) {
  data.forEach(item => ...)
  return data
}`)
$worker.invoke([...]).todo(data => {
  console.log(data)
})

When you return a promise in factory, promise.then data will be send back. So if you return a promise in factory, you can directly use promise success data in todo callback.

let $worker = create(`function(data) {
  return new Promise(resolve => {
    // ...
    resolve(data)
  })
}`)
$worker.invoke([...]).todo(data => { // use data directly in todo
  console.log(data)
})

todo(callback):

Here callback is a function which has one parameter.

After the factory function is run in worker thread, and postMessage back to main js thread, callback will be run.

However, if you use $notify in factory, callback will be run immediately when $notify is called.

callback is a function like:

$worker.todo(data => {})

It has a parameter which is the data returned or notified by factory.

todo can invoke multiple times, but only one callback function will be used. The last todo callback function will be use. Let's look into an example:

$worker.invoke(12) // invoke factory function, if you do not add todo, nothing will happen when function is finished
.todo(data => console.log(1))
.todo(data => console.log(2))

In the above example, 2 will always be show, because the last todo callback function will be the final function to use.

Notice: there is a special case, when you invoke factory, it is too quickly to finish the function so that the result is there, when this happen, the first todo callback will be run at first. In fact, it is not recommanded to run a small program in worker thread.

catch(callback):

catch is for error in worker thread. When a error is threw in worker thread, catch callback will run.

The error info will be passed into callback:

$worker.catch(e => console.log(e))

$worker.close()

Do NOT use $worker.terminate() to close worker thread, because we need to clean the context. $worker.terminate() only close the thread, but some other resource are not cleaned.

And do not close a worker instance after it created, you should close it after invoke success. For example (a bad example):

let $worker = create(`function(data) {
  return data
}`)
$worker.invoke({name: 'tom'}).todo(data => console.log(data))
$worker.close() // never do like this

The right way:

$worker.invoke({name: 'tom'})
.todo(data => {
  console.log(data)
  worker.close() // close worker after you get the result
})

run(factory, args)

Sometimes you do not need to create a worker instance, you just want to run a program in worker thread once. For example, you want to caculate a big data in worker:

run(`function(data) {
  // caculate data
  return data
}`, [..big data..])
.then(data => {
  // use caculate result
})

run function return a Promise, and caculated result is passed into then.

You do not need to close it, it has been closed inside. And params rule is the same with invoke.

In fact, run is a brief packaging of create, invoke, todo and close.

global vars

There are two global vars can be used in factory function. They are $xhr and $notify.

$xhr

To provide a XMLHttpRequest base api in your factory by using $xhr.

import {create} from 'quicker-worker'
import {createXHR} from 'quicker-worker/dist/xhr'

let $worker = create(`function(p1, p2) {
  ${createXHR()}
  return $xhr.post('your_url', {p1, p2})
}`)
$worker.invoke(['name', 'age']).then(data => {
  console.log(data)
})

Notice: you should use createXHR(), not createXHR.

Here, as you see, you can use $xhr directly in factory, and return the request as a Promise instance in factory. In $worker.invoke we have talked about return Promise in factory.

Now, let's talk about the detail of $xhr.

$xhr({
  url: '',
  type: 'GET',
  headers: {},
  timeout: 20000,
  async: true,
  before: function() {}, // which will be run after XMLHttpRequest instance created before timeout set
  beforeOpen: function() {}, // which will be run before XMLHttpRequest instance open
  beforeSend: function() {}, // which will be run before request sent
}).then(data => ...).catch(e => ...)

It is like jQuery $.ajax. And it provides .get and .post methods:

$xhr.get('url').then(...)
$xhr.post('url', postData).then(...)

url make sense! Because XMLHttpRequest in worker thread is not share context with main thread, so requests in worker will face cross-domain problem. It does only allow to request to current domain host, for example, you can not request for yourdomain.com to otherdomain.com. And even you can not visit with url like '/root/to/path', because there is no window.location in worker thread. Thought I have set withCredentials to be true, it seems not working.

To fix this problem, I have inject current host into worker program, so that you can pass a absolute url path like '/root/to/path' which will be treated as local url. So don't be worry about url, you can and must use absolute url to send request.

In fact, I recommand you to use fetch api directly in worker code, which is more easy.

$notify && $throw

To invoke todo callback function more free, I provide $notify and $throw functions so that you can post data back to main thread anytime. $notify means send back successful data, $throw means send back error.

let $worker = create(`function() {
  //..
  if (wrong) {
    $throw(err)
    return
  }
  $notify(1)
  return 2
}`)
$worker.invoke().todo(data => console.log(data)) // data will be 1

If you use $notify or $throw, return value in factory will be ignored. $notify or $throw has higher priority.

Think about a situation: make ajax in a worker to request latest data cyclicly, if data is changed, update your view. This is a good case to use $notify:

let $worker = create(`function() {
  setInterval(function() {
    // do something
    $notify(data)
  }, 60*1000)
}`)
$worker.invoke().todo(data => { ... })

In this case, todo callback will be called every 1 minute.

Others

After you create a worker thread, the function will not run until you call invoke. So do not invoke a worker thread factory which has setInterval too many times unless you know what you are doing.

When you post back data from worker thread to main thread, you'd better to remember that never send back an instance of a class. i.e.

// in worker factory
var e = new Error(msg)
$notify(e) // this is wrong

The previous code will throw an error because memory is not shared between different threads.

quicker-worker use blob to inject js, which make quicker-worker not work in IE10. So if you want to support IE10, you should have to research another library until I want to improve this library someday.

quicker-worker use native Promise, so that you can not use it in some environment which is not supporting native Promise until I want to improve this library someday.

If you want some referer, you can look into https://github.com/zhangyuanwei/EasyWorker which has more feature and supports node side.

Readme

Keywords

Package Sidebar

Install

npm i quicker-worker

Weekly Downloads

0

Version

0.1.0

License

MIT

Last publish

Collaborators

  • tangshuang