Kevnz
8/17/2012 - 2:06 AM

Loading YUI from the CDN into a Web Worker

Loading YUI from the CDN into a Web Worker

YUI().use('array-extras', 'gallery-async', 'gallery-yql-rest-client', 'node', function (Y) {
    
    // Create a Loader instance to easily build the required module URLs
    var loader = new Y.Loader({
        combine: true, // A good idea
        ignoreRegistered: true,
        require: [
            'json-stringify'
        ]
    })

    // Include the JS dependencies as well
    var urls = loader.resolve(true).js;

    // Don't forget the seed file! Push it onto the front
    urls.unshift('http://yui.yahooapis.com/3.5.1/build/yui/yui-min.js');
    
    // Create the async command queue that will fetch the scripts
    var queue = Y.Array.map(urls, function (url) {
        return (function (success) {
                    Y.YQLRESTClient.request({
                        method: 'get',
                        url: url
                    }, function (result) {
                        success(result.response);
                    });
                });
    });

    // Executed once the entire queue is complete and we have all the scripts
    var onComplete = function (eventFacade) {
        var blobBuilder = new (Y.config.win.BlobBuilder || Y.config.win.MozBlobBuilder || Y.config.win.WebKitBlobBuilder)(),
            yuiScripts = eventFacade.value.join('\n'), // This is a combined script of YUI modules
            myScript = Y.one('#my-script').get('text'),
            blob, objURL, webWorker;

        // Combine the YUI module scripts with my script at the end
        blobBuilder.append(yuiScripts + '\n' + myScript);

        // Get a blob of all the JS code
        blob = blobBuilder.getBlob();

        // Get a URL to represent the blob
        objectURL = Y.config.win.URL.createObjectURL(blob);
        
        // Create the worker and onmessage listener
        webWorker = new Worker(objectURL);
        webWorker.onmessage = function (message) {
            Y.one('body').append('<p>' + message.data + '</p>');
        };
    };
    
    // Execute the command queue
    Y.Async.runAll(queue).on('complete', onComplete);
});
<!-- Will only be available outside the worker -->
<script src="http://yui.yahooapis.com/3.5.1/build/yui/yui-min.js"></script>

<script src="script.js"></script>

<!-- This is the script we are going to run inside a WebWorker thread. -->
<!-- Give it a different 'type' since we don't want to execute it, yet. -->
<script id="my-script" type="application/web-worker">
    YUI().use('json-stringify', function (Y) {
        postMessage(Y.JSON.stringify([1, 2, 3, 4, 5]));
    });
</script>

Scenario

I want to use YUI inside of a WebWorker thread. Flickr recently wrote a post on this very topic, Web workers and YUI.

Problem

But I want to use YUI's CDN, which WebWorkers prevent because it enforces a same-origin policy with importScripts()

Solution

Two options:

Option A) Host YUI yourself. Boooo.

Option B) This script demonstrates a proof-of-concept technique that uses:

  • Y.Loader to generate the module URL(s)
  • Y.YQLRESTClient to fetch each URL
  • Y.Async to handle the queue
  • BlobBuilder to create a single blob of all scripts combined
  • createObjectURL to hand off the blob to the WebWorker

Credit to solmsted in #yui for original script (http://jsfiddle.net/uqt5c/)

Prettied by dgathright