Skip to content

Instantly share code, notes, and snippets.

@solmsted
Created October 6, 2012 18:45
Show Gist options
  • Save solmsted/3845763 to your computer and use it in GitHub Desktop.
Save solmsted/3845763 to your computer and use it in GitHub Desktop.
yui-soon
/**
* Provides a setImmediate/setTimeout wrapper. This module is a `core` YUI
* module, <a href="../classes/YUI.html#method_soon">its documentation is
* located under the YUI class</a>.
*
* @module yui
* @submodule yui-soon
* @author Steven Olmsted
*/
var subscribedToMessageEvent,
/**
* Y.soon accepts a callback function. The callback function will be
* called once in a future turn of the JavaScript event loop. If the
* function requires a specific execution context or arguments, wrap it
* with Y.bind. Y.soon returns an object with a cancel method. If the
* cancel method is called before the callback function, the callback
* function won't be called.
* @method soon
* @for YUI
* @param {Function} callbackFunction
* @return {Object}
* @param {Function} cancel If the cancel method is called before the
* callback function, the callback function won't be called.
*/
soon = function (callbackFunction) {
var canceled;
soon._asynchronizer(function () {
// Some asynchronizers may provide their own cancellation methods
// such as clearImmediate or clearTimeout but some asynchronizers
// do not. For simplicity, cancellation is entirely handled here
// rather than wrapping the other methods. All asynchronizers are
// expected to always call this anonymous function.
if (!canceled) {
callbackFunction();
}
}, 0);
// The 0 is required when setTimeout is used, but it should be ignored
// by other asynchronizers.
return {
cancel: function () {
canceled = 1;
}
};
};
/**
* The asynchronizer is the internal mechanism which will call a function
* asynchronously. This property is exposed as a convenient way to define a
* different asynchronizer implementation without having to rewrite the entire
* Y.soon interface.
* @method _asynchronizer
* @for soon
* @param {Function} callbackFunction The function to call asynchronously.
* @protected
*/
/**
* Since Y.soon is likely to have many differing asynchronizer implementations,
* this property should be set to identify which implementation is in use.
* @property _impl
* @protected
* @type String
*/
// Check for a native or already polyfilled implementation of setImmediate.
if ('setImmediate' in Y.config.win) {
soon._asynchronizer = Y.config.win.setImmediate;
soon._impl = 'setImmediate';
} else if ('mozSetImmediate' in Y.config.win) {
soon._asynchronizer = Y.config.win.mozSetImmediate;
soon._impl = 'mozSetImmediate';
} else if ('msSetImmediate' in Y.config.win) {
soon._asynchronizer = Y.config.win.msSetImmediate;
soon._impl = 'msSetImmediate';
} else if ('oSetImmediate' in Y.config.win) {
soon._asynchronizer = Y.config.win.oSetImmediate;
soon._impl = 'oSetImmediate';
} else if ('webkitSetImmediate' in Y.config.win) {
soon._asynchronizer = Y.config.win.webkitSetImmediate;
soon._impl = 'webkitSetImmediate';
}
// Check for postMessage but make sure we're not in a WebWorker.
else if (('postMessage' in Y.config.win) && !('importScripts' in Y.config.win)) {
soon._asynchronizer = function (callbackFunction) {
if (!subscribedToMessageEvent) {
// Subscribe to the message event.
YUI.Env.add(Y.config.win, 'message', function (event) {
// Only pay attention to messages from this window.
if (event.source === Y.config.win) {
// The message we've received in event.data could be
// anything. If it's a Y.soon message id, there will be a
// callback function associated with it.
var id = event.data,
callbackFunction = soon._asynchronizer[id];
if (callbackFunction) {
// There is a callback function, so call it.
callbackFunction();
// We no longer need to keep the callback function.
delete soon._asynchronizer[id];
// Other listeners should't care about this message.
if (event.stopImmediatePropagation) {
event.stopImmediatePropagation();
} else {
event.stopPropagation();
}
event.preventDefault();
}
}
}, false);
subscribedToMessageEvent = true;
}
// Create a unique Y.soon message id for this callback function.
var id = Y.guid('soon');
// Store the callback function to be called later by the event handler.
soon._asynchronizer[id] = callbackFunction;
// Send the message, but make sure it does not get sent to listeners
// from another origin.
Y.config.win.postMessage(id, Y.config.win.location);
};
soon._impl = 'postMessage';
}
// The most widely supported asynchronizer is setTimeout so we use that as the
// fallback.
else {
soon._asynchronizer = setTimeout;
soon._impl = 'setTimeout';
}
Y.soon = soon;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment