diff --git a/doc/api/timers.markdown b/doc/api/timers.markdown index cf2f24ae938adb..7e4efb47c12929 100644 --- a/doc/api/timers.markdown +++ b/doc/api/timers.markdown @@ -37,6 +37,8 @@ The entire callback queue is processed every event loop iteration. If you queue an immediate from inside an executing callback, that immediate won't fire until the next event loop iteration. +If `callback` is not a function `setImmediate()` will throw immediately. + ## setInterval(callback, delay[, arg][, ...]) To schedule the repeated execution of `callback` every `delay` milliseconds. @@ -47,6 +49,8 @@ To follow browser behavior, when using delays larger than 2147483647 milliseconds (approximately 25 days) or less than 1, Node.js will use 1 as the `delay`. +If `callback` is not a function `setInterval()` will throw immediately. + ## setTimeout(callback, delay[, arg][, ...]) To schedule execution of a one-time `callback` after `delay` milliseconds. @@ -62,6 +66,8 @@ To follow browser behavior, when using delays larger than 2147483647 milliseconds (approximately 25 days) or less than 1, the timeout is executed immediately, as if the `delay` was set to 1. +If `callback` is not a function `setTimeout()` will throw immediately. + ## unref() The opaque value returned by [`setTimeout`][] and [`setInterval`][] also has the diff --git a/lib/timers.js b/lib/timers.js index 24dc7e1c263c7e..66f77dfd0656df 100644 --- a/lib/timers.js +++ b/lib/timers.js @@ -177,6 +177,10 @@ exports.enroll = function(item, msecs) { exports.setTimeout = function(callback, after) { + if (typeof callback !== 'function') { + throw new TypeError('"callback" argument must be a function'); + } + after *= 1; // coalesce to number or NaN if (!(after >= 1 && after <= TIMEOUT_MAX)) { @@ -233,6 +237,10 @@ exports.clearTimeout = function(timer) { exports.setInterval = function(callback, repeat) { + if (typeof callback !== 'function') { + throw new TypeError('"callback" argument must be a function'); + } + repeat *= 1; // coalesce to number or NaN if (!(repeat >= 1 && repeat <= TIMEOUT_MAX)) { @@ -419,6 +427,10 @@ Immediate.prototype._idlePrev = undefined; exports.setImmediate = function(callback, arg1, arg2, arg3) { + if (typeof callback !== 'function') { + throw new TypeError('"callback" argument must be a function'); + } + var i, args; var len = arguments.length; var immediate = new Immediate(); diff --git a/test/parallel/test-timers-throw-when-cb-not-function.js b/test/parallel/test-timers-throw-when-cb-not-function.js new file mode 100644 index 00000000000000..7397c23b4933c9 --- /dev/null +++ b/test/parallel/test-timers-throw-when-cb-not-function.js @@ -0,0 +1,62 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); + +function doSetTimeout(callback, after) { + return function() { + setTimeout(callback, after); + }; +} + +assert.throws(doSetTimeout('foo'), + /"callback" argument must be a function/); +assert.throws(doSetTimeout({foo: 'bar'}), + /"callback" argument must be a function/); +assert.throws(doSetTimeout(), + /"callback" argument must be a function/); +assert.throws(doSetTimeout(undefined, 0), + /"callback" argument must be a function/); +assert.throws(doSetTimeout(null, 0), + /"callback" argument must be a function/); +assert.throws(doSetTimeout(false, 0), + /"callback" argument must be a function/); + + +function doSetInterval(callback, after) { + return function() { + setInterval(callback, after); + }; +} + +assert.throws(doSetInterval('foo'), + /"callback" argument must be a function/); +assert.throws(doSetInterval({foo: 'bar'}), + /"callback" argument must be a function/); +assert.throws(doSetInterval(), + /"callback" argument must be a function/); +assert.throws(doSetInterval(undefined, 0), + /"callback" argument must be a function/); +assert.throws(doSetInterval(null, 0), + /"callback" argument must be a function/); +assert.throws(doSetInterval(false, 0), + /"callback" argument must be a function/); + + +function doSetImmediate(callback, after) { + return function() { + setImmediate(callback, after); + }; +} + +assert.throws(doSetImmediate('foo'), + /"callback" argument must be a function/); +assert.throws(doSetImmediate({foo: 'bar'}), + /"callback" argument must be a function/); +assert.throws(doSetImmediate(), + /"callback" argument must be a function/); +assert.throws(doSetImmediate(undefined, 0), + /"callback" argument must be a function/); +assert.throws(doSetImmediate(null, 0), + /"callback" argument must be a function/); +assert.throws(doSetImmediate(false, 0), + /"callback" argument must be a function/);