Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added soon.

  • Loading branch information...
commit 72d6d67908a7a64453e9f2b6da5f4d491f2a3d41 1 parent dae59cd
@solmsted authored
View
3  src/soon/HISTORY.md
@@ -0,0 +1,3 @@
+soon
+========
+* Initial release.
View
6 src/soon/README.md
@@ -0,0 +1,6 @@
+soon
+========
+Similar to `Y.later`, but sooner. `Y.soon` standardizes the way to make
+something happen asynchronously but without a timed delay. Under the covers,
+`Y.soon` will call `setTimeout` if it must, but it will try to use the more
+efficient `setImmediate` or `process.nextTick` depending on the environment.
View
10 src/soon/build.json
@@ -0,0 +1,10 @@
+{
+ "builds": {
+ "soon": {
+ "jsfiles": [
+ "js/soon.js"
+ ]
+ }
+ },
+ "name": "soon"
+}
View
88 src/soon/js/soon.js
@@ -0,0 +1,88 @@
+/**
+ * Provides a setImmediate/process.nextTick/setTimeout wrapper.
+ * @module soon
+ * @author Steven Olmsted
+ */
+
+var global = Y.config.global,
+
+ /**
+ * 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} An object with a cancel method. 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();
+ }
+ });
+
+ 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 global) {
+ soon._asynchronizer = function (callbackFunction) {
+ setImmediate(callbackFunction);
+ };
+ soon._impl = 'setImmediate';
+}
+
+// Check for process and process.nextTick
+else if (('process' in global) && ('nextTick' in process)) {
+ soon._asynchronizer = process.nextTick;
+ soon._impl = 'nextTick';
+}
+
+// The most widely supported asynchronizer is setTimeout so we use that as
+// the fallback.
+else {
+ soon._asynchronizer = function (callbackFunction) {
+ setTimeout(callbackFunction, 0);
+ };
+ soon._impl = 'setTimeout';
+}
+
+Y.soon = soon;
View
7 src/soon/meta/soon.json
@@ -0,0 +1,7 @@
+{
+ "soon": {
+ "requires": [
+ "yui-base"
+ ]
+ }
+}
View
29 src/soon/tests/unit/index.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>
+ soon
+ </title>
+ <script src="/build/yui/yui.js">
+ </script>
+ <script src="js/tests.js">
+ </script>
+ </head>
+ <body class="yui3-skin-sam">
+ <div id="logger">
+ </div>
+ <script>
+ YUI({
+ coverage: [
+ 'soon'
+ ],
+ filter: (window.location.search.match(/[?&]filter=([^&]+)/) || [])[1] || 'raw'
+ }).use('test-console', 'test', 'module-tests', function (Y) {
+ (new Y.Test.Console()).render('#logger');
+ Y.Test.Runner.setName('soon');
+ Y.Test.Runner.run();
+ });
+ </script>
+ </body>
+</html>
View
60 src/soon/tests/unit/js/tests.js
@@ -0,0 +1,60 @@
+YUI.add('module-tests', function (Y) {
+ 'use strict';
+
+ var suite = new Y.Test.Suite('soon');
+
+ suite.add(new Y.Test.Case({
+ name: 'Automated Tests',
+ 'test:001-apiExists': function () {
+ Y.Assert.isFunction(Y.soon, 'Y.soon should be a function.');
+ Y.Assert.isFunction(Y.soon._asynchronizer, 'Y.soon._asynchronizer should be a function.');
+ Y.Assert.isString(Y.soon._impl, 'Y.soon._impl should be a string.');
+ },
+ 'test:002-asyncCallbackFunction': function () {
+ var count = 0,
+ test = this,
+ timer = Y.soon(function () {
+ count += 1;
+
+ if (count > 1) {
+ test.resume(function () {
+ Y.Assert.fail('Y.soon() callback function should not execute multiple times.');
+ });
+ } else {
+ test.resume(function () {
+ // Arbitrary timeout to test that the callback
+ // function does not execute again.
+ test.wait(function () {
+ Y.Assert.isTrue(true);
+ }, 150);
+ });
+ }
+ });
+
+ Y.Assert.areSame(0, count);
+ Y.Assert.isObject(timer);
+ Y.Assert.isFunction(timer.cancel);
+
+ test.wait();
+ },
+ 'test:003-cancel': function () {
+ var count = 0,
+ timer = Y.soon(function () {
+ count += 1;
+ });
+
+ timer.cancel();
+
+ this.wait(function () {
+ Y.Assert.areSame(0, count);
+ }, 250);
+ }
+ }));
+
+ Y.Test.Runner.add(suite);
+}, '', {
+ requires: [
+ 'soon',
+ 'test'
+ ]
+});
Please sign in to comment.
Something went wrong with that request. Please try again.