diff --git a/lib/next-tick.js b/lib/next-tick.js new file mode 100644 index 00000000..659ed4df --- /dev/null +++ b/lib/next-tick.js @@ -0,0 +1,26 @@ +exports.messageChannel = function() { + var triggerCallback = createNextTickTrigger(arguments); + var channel = new MessageChannel(); + channel.port1.onmessage = function() { + triggerCallback(); + channel.port1.close(); + }; + channel.port2.postMessage(''); +}; + +exports.setTimeout = function() { + var triggerCallback = createNextTickTrigger(arguments); + setTimeout(triggerCallback); +}; + +function createNextTickTrigger(args) { + var callback = args[0]; + var _args = []; + for (var i = 1; i < args.length; i++) { + _args[i - 1] = args[i]; + } + + return function triggerCallback() { + callback.apply(null, _args); + }; +} diff --git a/lib/util.js b/lib/util.js index 2ddc62e6..0d613ed5 100644 --- a/lib/util.js +++ b/lib/util.js @@ -1,3 +1,4 @@ +var nextTickImpl = require('./next-tick'); exports.doNothing = doNothing; function doNothing() {} @@ -85,31 +86,13 @@ exports.truthy = function(arg) { return !!arg; }; -exports.nextTick = function(callback) { - if (typeof process !== 'undefined' && process.nextTick) { - return process.nextTick.apply(null, arguments); - } - - var args = []; - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - - if (typeof MessageChannel === 'undefined') { - return setTimeout(triggerCallback); - } - - var channel = new MessageChannel(); - channel.port1.onmessage = function() { - triggerCallback(); - channel.port1.close(); - }; - channel.port2.postMessage(''); - - function triggerCallback() { - callback.apply(null, args); - } -}; +if (typeof process !== 'undefined' && typeof process.nextTick === 'function') { + exports.nextTick = process.nextTick; +} else if (typeof MessageChannel !== 'undefined') { + exports.nextTick = nextTickImpl.messageChannel; +} else { + exports.nextTick = nextTickImpl.setTimeout; +} exports.clone = function(obj) { return (obj === undefined) ? undefined : JSON.parse(JSON.stringify(obj)); diff --git a/test/next-tick.js b/test/next-tick.js new file mode 100644 index 00000000..f3ba0fe8 --- /dev/null +++ b/test/next-tick.js @@ -0,0 +1,26 @@ +var nextTickImpl = require('../lib/next-tick'); +var expect = require('chai').expect; + +describe('nextTick', function() { + ['messageChannel', 'setTimeout'].forEach(function(name) { + var tick = nextTickImpl[name]; + + it('passes args', function(done) { + tick(function(arg1, arg2, arg3) { + expect(arg1).to.equal('foo'); + expect(arg2).to.equal(123); + expect(arg3).to.be.undefined; + done(); + }, 'foo', 123); + }); + + it('calls asynchronously', function(done) { + var called = false; + tick(function() { + called = true; + done(); + }); + expect(called).to.be.false; + }); + }); +}); diff --git a/test/util-test.js b/test/util-test.js deleted file mode 100644 index 2ce2d71d..00000000 --- a/test/util-test.js +++ /dev/null @@ -1,83 +0,0 @@ -var util = require('../lib/util'); -var expect = require('chai').expect; - -describe('util', function() { - describe('nextTick', function() { - it('uses process.nextTick if present', function(done) { - expect(process.nextTick).to.be.ok; - - util.nextTick(function(arg1, arg2, arg3) { - expect(arg1).to.equal('foo'); - expect(arg2).to.equal(123); - expect(arg3).to.be.undefined; - done(); - }, 'foo', 123); - }); - - describe('without nextTick', function() { - var nextTick; - - before(function() { - nextTick = process.nextTick; - delete process.nextTick; - }); - - after(function() { - process.nextTick = nextTick; - }); - - it('uses a ponyfill if process.nextTick is not present', function(done) { - expect(process.nextTick).to.be.undefined; - - util.nextTick(function(arg1, arg2, arg3) { - expect(arg1).to.equal('foo'); - expect(arg2).to.equal(123); - expect(arg3).to.be.undefined; - done(); - }, 'foo', 123); - }); - - it('calls asynchronously', function(done) { - var called = false; - util.nextTick(function() { - called = true; - done(); - }); - expect(called).to.be.false; - }); - - describe('without MessageChannel', function() { - var _MessageChannel; - - before(function() { - _MessageChannel = global.MessageChannel; - delete global.MessageChannel; - }); - - after(function() { - global.MessageChannel = _MessageChannel; - }); - - it('uses a different ponyfill', function(done) { - expect(process.nextTick).to.be.undefined; - - util.nextTick(function(arg1, arg2, arg3) { - expect(arg1).to.equal('foo'); - expect(arg2).to.equal(123); - expect(arg3).to.be.undefined; - done(); - }, 'foo', 123); - }); - - it('calls asynchronously', function(done) { - var called = false; - util.nextTick(function() { - called = true; - done(); - }); - expect(called).to.be.false; - }); - }); - }); - }); -});