Javascript Web Workers: From Basics to jQuery.Hive, Part III


I’m a jQuery enthusiast. Maybe even an evangelist. So I decided to make workers easy for my fellow jQuery developers – and thus was born the jQuery.Hive. Inititally it began it’s life as PollenJS a jQuery-looking library of functions that were light, useful and thread-safe. This was before the WebKit implementation existed so everything was written with the notion that it would only exist in the Worker. The MOST IMPORTANT goals were and still are:

  • Concise syntax
  • Shallow learning curve for jQuery developers

Not long after I began developing PollenJS, Safari WebKit added Worker support and shortly thereafter Chrome WebKit caught up. Of course then PollenJS was officially broken – it normalized messages into objects to add support for identity from one worker to the other… WebKit sent errant empty messages.


This is when the Hive was born.


… Which was awesome, because it gave me the opportunity to make the main window as easy to manage development with workers as PollenJS had become within the worker. The basic goals were:

  • Simplify the client/main page worker setup API
  • Wrap the Worker constructor and functions in syntax that jQuery developers are familiar with
  • Normalize cross-implementation inconsistencies

jQuery.Hive/PollenJS turbocharge your workers.

Let’s look at the data filter example from above, but in jQuery.Hive/Pollen JS syntax…

workers-5.js

//  The main window
$(function () {

  var message = {
        data: { /* huge data object */ },
        filter: 'foo'
      };

  $.Hive.create({
    //  optional. if no 'count' property is set, Hive creates only 1 worker
    count: 1,
    //  the worker file
    worker: 'hive-worker-file-1.js',
    //  the receive ( convenience to writing out the addEventListener)
    receive: function (filtered) {
      /*

        jQuery.Hive manages serialization/deserialization

      */      console.log(filtered.data);

    },
    created: function ( $hive ) {
      /*

        the `created` callback fires after the worker is created,
        the first argument is an array of the workers

        $().send() is the wrapper for postMessage() with complete
        serialization/deserialization

      */      $( $hive ).send(message);

    }
  });

  /*
    without comments:

    $.Hive.create({
      worker: 'hive-worker-file-1.js',
      receive: function (filtered) {
        console.log(filtered.data);
      },
      created: function ( $hive ) {
        $( $hive ).send(message);
      }
    });

  */});

It’s important to remember that including ‘jquery.hive.pollen.js’ is REQUIRED, or else you will not get compatibility across implementations. And plus, it’s got rad stuff in it.

workers-6.js

//  Inside the worker

importScripts('jquery.hive.pollen.js');

//  Alias to addEventListener() syntax
$(function (message) {

  //  $.send() is the wrapper for postMessage() with complete
  //  serialization/deserialization

  $.send(
    //  $.query() is part of the PollenJS API
    $.query(
      //  Filter data with a JSONPath query
      "[="+message.filter+"]",
      message.data
    )
  );
});


/*
  without comments:


  importScripts('jquery.hive.pollen.js');

  $(function (message) {
    $.send(
      $.query(
        "[="+message.filter+"]",
        message.data
      )
    );
  });
*/


Get jQuery.Hive/PollenJS from GitHub – Starter Kit included!

The [In]Complete jQuery.Hive API

workers-7.js

jQuery.Hive -> The Hive is a property of jQuery

jQuery.Hive.options -> Setup properties for jQuery.Hive.create( [options] )

jQuery.Hive.options.count -> Set property from jQuery.Hive.create( { count: [int] } ), number of threads to create

jQuery.Hive.options.worker -> Set string property from jQuery.Hive.create( { worker: [file-name] } ), name of worker file

jQuery.Hive.options.receive -> Set callback from jQuery.Hive.create( { receive: [callback] } ), callback to execute when worker receives message (can be global or worker specific)

jQuery.Hive.options.created -> Set callback from jQuery.Hive.create( { created: [callback] } ), callback to execute when workers have been created

jQuery.Hive.options.special -> NOT IMPLEMENTED/INCOMPLETE - Set callback as a second argument to $().send()

jQuery.Hive.options.error() -> NOT IMPLEMENTED/INCOMPLETE - Error handler

jQuery.Hive.create( options ) -> Array, create workers, returns array of all workers

jQuery.Hive.destroy( [id] ) -> destroy all or specified worker by id

jQuery.Hive.get( [id] ) -> Return all or specified worker by [id], [id] argument is optional
--> $.Hive.get() returns all worker objects in the $.Hive
--> $.Hive.get(1) returns the worker object whose ID is 1

jQuery.Hive.get( id ).send( message, callback ) -> Send [message] to worker thread, set optional receive callback
--> SIMPLER ALTERNATIVE: $.Hive.get(id).send( [message], function () {} )
--> Allows for passing a jQuery.Hive.get(id) object to $() ie. $( $.Hive.get(id) ).send( [message] )

jQuery.( $.Hive.get() ).send( message ) -> Send [message] to worker thread
--> SIMPLER ALTERNATIVE: $.Hive.get(id).send( [message] )
--> Allows for passing a $.Hive.get(id) object to $() ie. $( $.Hive.get(id) ).send( [message] )

The [In]Complete jQuery.Hive.Pollen.js API

workers-8.js



$.now([uts]) -> Microseconds or UTS if $.now(true) $.noop() -> Empty function, Lifted from jQuery 1.4+, returns empty function (replaced $.emptyFn()) $.bind( function, context, args ) -> Function with explicit context, context sets 'this' $.isObj( arg ) -> Boolean, object was created with {} or new Object() $.isEmptyObj( arg ) -> Boolean, Empty Object $.isArr( arg ) -> Boolean, Array $.isRegExp( arg ) -> Boolean, Regular Expression $.isFn( arg ) -> Boolean, Function $.isStr( arg ) -> Boolean, String $.isNum( arg ) -> Boolean, Number $.isJson( arg ) -> Boolean, Valid JSON String $.isDef( arg ) -> Boolean, Defined $.isNull( arg ) -> Boolean, Null $.isEmpty( arg ) -> Boolean, '' $.eq( arg, array ) -> Arg is equal to at least one definition in array $.trim( arg ) -> Removes all L and R whitespace $.inStr( arg ) -> Boolean, arg in string $.each( object, function ) -> Enumerate [object] (object,array), apply [function] $.toArray( arg ) -> Convert [arg] into an array $.isAtIndex( array, index, needle ) -> Boolean, Checks if [needle] is located at [index] in [array] $.getIndex( array, needle ) -> Int, index of [needle] in [array] $.inArr( array, needle ) -> Boolean, true if [needle] in [array] $.clone( arg ) -> Array || Object, clone of [array] or Object, deep clone of [object] $.last( array ) -> Array Item, last item in [array] $.first( array ) -> Array Item, first item in [array] $.unique( arg ) -> Array || Object, removes duplicate values from [arg](array||object), returns uniques $.merge( arr, ) -> Array, Merges [*](array), removes duplicate values $.combine( keys, values ) -> Object, An object, where [keys](array) = [values](array) $.filter( arg , function, iteration ) -> (Array||Object), apply [function](true||false) to each item in [arg], return (array||object) of true $.map( array, function ) -> Array, apply [function] to each item in [array], return array of new values $.grep( array, expression, function ) -> Object, values that match [expression] and/or [function] $.size( array ) -> Int, size of arr $.extend( object, _object ) -> Object, copy properties fron [_object] to [object] $.ajax.get( request ) -> Implemented. Documention incomplete. --> request.url -> url to open --> request.data -> params --> request.success -> success callback $.ajax.post( request ) -> Implemented. Documention incomplete. --> request.url -> url to open --> request.data -> params --> request.success -> success callback $.param( arg ) -> String, Derived and Adapted from, similar in behavior to jQuery.param() $.storage( key, val ) -> ?, persistant across worker messages (by worker) data storage - setter $.storage( key ) -> Val, persistant across worker messages (by worker) data storage - getters $.query( selector, object ) -> *, Query json or object with JSONPath selector --> http://goessner.net/articles/JsonPath/ $.send( message ) -> Wraps and normalizes postMessage() across supporting clients, sends [message](object||string||array) to client --> if [message] is an object, and message.SEND_TO & message.SEND_FROM is defined, the message will be sent directly to the worker defined by SEND_TO $.receive( function() {} ) -> Worker, execute [function] when worker receives a message from the client --> first argument is message object --> 'this' is WorkerGlobalScope --> can be shortened to $(function (message) { } ); $.decode( arg ) -> JSON as String, turns JSON [arg] into a str $.encode( arg ) -> JSON Object, turns [arg] into JSON

Considering it’s youth as a project, the API is subject to change.

EditIn the time since this was originally published, Chrome, Safari & Opera now support complex JSON messages.

Comments

Contact Us

We'd love to hear from you. Get in touch!

Phone

+1 617-283-2807

Mail

P.O. Box 961436
Boston, MA 02196