Rectangle 27 0

Web workers without a separate Javascript file?


// Build a worker from an anonymous function body
var blobURL = URL.createObjectURL( new Blob([ '(',

function(){
    //Long-running work here
}.toString(),

')()' ], { type: 'application/javascript' } ) ),

worker = new Worker( blobURL );

// Won't be needing this anymore
URL.revokeObjectURL( blobURL );
// Post code from window to ServiceWorker...
navigator.serviceWorker.controller.postMessage(
 [ '/my_workers/worker1.js', '(' + workerFunction1.toString() + ')()' ]
);

// Insert via ServiceWorker.onmessage. Or directly once window.caches is exposed
caches.open( 'myCache' ).then( function( cache )
{
 cache.put( '/my_workers/worker1.js',
  new Response( workerScript, { headers: {'content-type':'application/javascript'}})
 );
});

Can you elaborate on this solution, how does it work? What is the worker1.js? Is it a seperate js file? I am trying to use this but unable to make it work. Specifically I am trying to make it work for a SharedWorker

If only you could wrap it up in a useful function!

Now there's an even more powerful way of solving this problem. Again, store the worker code as a function, (rather than a static string) and convert using .toString(), then insert the code into CacheStorage under a static URL of your choice.

Personally I really like the toString methods, but @dan-man THAT regex!

Support is the intersection of these three tables:

The html5rocks solution of embedding the web worker code in HTML is fairly horrible. And a blob of escaped JavaScript-as-a-string is no better, not least because it complicates work-flow (Closure compiler can't operate on strings).

This won't work for a SharedWorker however, because the URL must be an exact match, even if the optional 'name' parameter matches. For a SharedWorker, you'll need a separate JavaScript file.

Note
Rectangle 27 0

Web workers without a separate Javascript file?


<!DOCTYPE html>
<script id="worker1" type="javascript/worker">
  // This script won't be parsed by JS engines because its type is javascript/worker.
  self.onmessage = function(e) {
    self.postMessage('msg from worker');
  };
  // Rest of your worker code goes here.
</script>
<script>
  var blob = new Blob([
    document.querySelector('#worker1').textContent
  ], { type: "text/javascript" })

  // Note: window.webkitURL.createObjectURL() in Chrome 10+.
  var worker = new Worker(window.URL.createObjectURL(blob));
  worker.onmessage = function(e) {
    console.log("Received: " + e.data);
  }
  worker.postMessage("hello"); // Start the worker.
</script>

@4esn0k - FF6, check my link above for the prefix issue...

Blob constructor might be supported in IE10, but you still cannot pass javascript to the web worker through it (not even in IE11): connect.microsoft.com/IE/feedback/details/801810/.

BlobBuiler is now deprecated. Use Blob instead. Currently supported in latest Firefox/WebKit/Opera and IE10, see compatibility tables for older browsers.

What if you want to create your worker script on the fly, or create a self-contained page without having to create separate worker files? With Blob(), you can "inline" your worker in the same HTML file as your main logic by creating a URL handle to the worker code as a string

Note
Rectangle 27 0

Web workers without a separate Javascript file?


var newWorker = function (funcObj) {
    // Build a worker from an anonymous function body
    var blobURL = URL.createObjectURL(new Blob(
        ['(', funcObj.toString(), ')()'],
        {type: 'application/javascript'}
     ));

    var worker = new Worker(blobURL);

    // Won't be needing this anymore
    URL.revokeObjectURL(blobURL);

    return worker;
}

Taking Adria's response and putting it in a copy-pastable function which works with current Chrome and FF but not IE10 (worker from blob causes a security error).

Note
Rectangle 27 0

Web workers without a separate Javascript file?


// Build a worker from an anonymous function body
var blobURL = URL.createObjectURL( new Blob([ '(',

function(){
    //Long-running work here
}.toString(),

')()' ], { type: 'application/javascript' } ) ),

worker = new Worker( blobURL );

// Won't be needing this anymore
URL.revokeObjectURL( blobURL );
// Post code from window to ServiceWorker...
navigator.serviceWorker.controller.postMessage(
 [ '/my_workers/worker1.js', '(' + workerFunction1.toString() + ')()' ]
);

// Insert via ServiceWorker.onmessage. Or directly once window.caches is exposed
caches.open( 'myCache' ).then( function( cache )
{
 cache.put( '/my_workers/worker1.js',
  new Response( workerScript, { headers: {'content-type':'application/javascript'}})
 );
});

Can you elaborate on this solution, how does it work? What is the worker1.js? Is it a seperate js file? I am trying to use this but unable to make it work. Specifically I am trying to make it work for a SharedWorker

If only you could wrap it up in a useful function!

Now there's an even more powerful way of solving this problem. Again, store the worker code as a function, (rather than a static string) and convert using .toString(), then insert the code into CacheStorage under a static URL of your choice.

Personally I really like the toString methods, but @dan-man THAT regex!

Support is the intersection of these three tables:

The html5rocks solution of embedding the web worker code in HTML is fairly horrible. And a blob of escaped JavaScript-as-a-string is no better, not least because it complicates work-flow (Closure compiler can't operate on strings).

This won't work for a SharedWorker however, because the URL must be an exact match, even if the optional 'name' parameter matches. For a SharedWorker, you'll need a separate JavaScript file.

Note
Rectangle 27 0

Web workers without a separate Javascript file?


<!DOCTYPE html>
<script id="worker1" type="javascript/worker">
  // This script won't be parsed by JS engines because its type is javascript/worker.
  self.onmessage = function(e) {
    self.postMessage('msg from worker');
  };
  // Rest of your worker code goes here.
</script>
<script>
  var blob = new Blob([
    document.querySelector('#worker1').textContent
  ], { type: "text/javascript" })

  // Note: window.webkitURL.createObjectURL() in Chrome 10+.
  var worker = new Worker(window.URL.createObjectURL(blob));
  worker.onmessage = function(e) {
    console.log("Received: " + e.data);
  }
  worker.postMessage("hello"); // Start the worker.
</script>

@4esn0k - FF6, check my link above for the prefix issue...

Blob constructor might be supported in IE10, but you still cannot pass javascript to the web worker through it (not even in IE11): connect.microsoft.com/IE/feedback/details/801810/.

BlobBuiler is now deprecated. Use Blob instead. Currently supported in latest Firefox/WebKit/Opera and IE10, see compatibility tables for older browsers.

What if you want to create your worker script on the fly, or create a self-contained page without having to create separate worker files? With Blob(), you can "inline" your worker in the same HTML file as your main logic by creating a URL handle to the worker code as a string

Note
Rectangle 27 0

Web workers without a separate Javascript file?


var newWorker = function (funcObj) {
    // Build a worker from an anonymous function body
    var blobURL = URL.createObjectURL(new Blob(
        ['(', funcObj.toString(), ')()'],
        {type: 'application/javascript'}
     ));

    var worker = new Worker(blobURL);

    // Won't be needing this anymore
    URL.revokeObjectURL(blobURL);

    return worker;
}

Taking Adria's response and putting it in a copy-pastable function which works with current Chrome and FF but not IE10 (worker from blob causes a security error).

Note
Rectangle 27 0

Web workers without a separate Javascript file?


If the origin of the resulting absolute URL is not the same as the origin of the entry script, then throw a SECURITY_ERR exception.

The spec from WHATWG says

This again means that web workers need to be initialized with code in source form.

This means that code cannot be moved from one context to another in object form, as they would then be able to reference objects via closures belonging to the other context. This is especially crucial as ECMAScript is designed to be a single threaded language, and since web workers operate in separate threads, you would then have the risk of non-thread-safe operations being performed.

Thus, scripts must be external files with the same scheme as the original page: you can't load a script from a data: URL or javascript: URL, and an https: page couldn't start workers using scripts with http: URLs.

Web workers operate in entirely separate contexts as individual Program's.

but unfortunately it doesn't really explain why one couldn't have allowed passing a string with source code to the constructor.

Note
Rectangle 27 0

Web workers without a separate Javascript file?


Take a look at the vkThread plugin. With htis plugin you can take any function in your main code and execute it in a thread (web worker). So, you don't need to create a special "web-worker file".

Note
Rectangle 27 0

Web workers without a separate Javascript file?


var BuildWorker = function(foo){
   var str = foo.toString()
             .match(/^\s*function\s*\(\s*\)\s*\{(([\s\S](?!\}$))*[\s\S])/)[1];
   return  new Worker(window.URL.createObjectURL(
                      new Blob([str],{type:'text/javascript'})));
}
var myWorker = BuildWorker(function(){
   //first line of worker
   self.onmessage(){....};
   //last line of worker
});

The above link is to a gist I created. Someone else later turned it into an actual repo.

Using the Blob method, how about this for a worker factory:

Note
Rectangle 27 0

Web workers without a separate Javascript file?


var BuildWorker = function(foo){
   var str = foo.toString()
             .match(/^\s*function\s*\(\s*\)\s*\{(([\s\S](?!\}$))*[\s\S])/)[1];
   return  new Worker(window.URL.createObjectURL(
                      new Blob([str],{type:'text/javascript'})));
}
var myWorker = BuildWorker(function(){
   //first line of worker
   self.onmessage(){....};
   //last line of worker
});

The above link is to a gist I created. Someone else later turned it into an actual repo.

Using the Blob method, how about this for a worker factory:

Note