diff --git a/lib/monitor/watch.js b/lib/monitor/watch.js index 799b7fd..4edc027 100644 --- a/lib/monitor/watch.js +++ b/lib/monitor/watch.js @@ -8,8 +8,8 @@ var fs = require('fs'), config = require('../config'), childProcess = require('child_process'), exec = childProcess.exec, - restartTimer = null, watched = [], + throttleRestartBus, watchers = []; var changeFunction = function () { @@ -195,6 +195,51 @@ function ignoredFileTypesForFind(dir) { return ' \\( ' + paths.join(' -or ') + ' \\) -or '; } +// Inspired by http://underscorejs.org/docs/underscore.html +function throttle(func, wait, options) { + var context, args, result; + var timeout = null; + var previous = 0; + if (!options) options = {}; + var later = function() { + previous = options.leading === false ? 0 : new Date().getTime(); + timeout = null; + result = func.apply(context, args); + if (!timeout) context = args = null; + }; + return function() { + var now = new Date().getTime(); + if (!previous && options.leading === false) previous = new Date().getTime(); + var remaining = wait - (now - previous); + context = this; + args = arguments; + if (remaining <= 0 || remaining > wait) { + clearTimeout(timeout); + timeout = null; + previous = now; + result = func.apply(context, args); + if (!timeout) context = args = null; + } else if (!timeout && options.trailing !== false) { + timeout = setTimeout(later, remaining); + } + return result; + }; +} + +function restartBus(matched) { + utils.log.status('restarting due to changes...'); + matched.result.map(function (file) { + utils.log.detail(path.relative(process.cwd(), file)); + }); + + if (config.options.verbose) { + utils.log._log(''); + } + + bus.emit('restart', matched.result); +} + + function filterAndRestart(files) { if (files.length) { if (utils.isWindows) { @@ -217,23 +262,15 @@ function filterAndRestart(files) { config.lastStarted = Date.now(); if (matched.result.length) { - if (restartTimer !== null) { - clearTimeout(restartTimer); - } - restartTimer = setTimeout(function () { - utils.log.status('restarting due to changes...'); - matched.result.map(function (file) { - utils.log.detail(path.relative(process.cwd(), file)); - }); - - if (config.options.verbose) { - utils.log._log(''); + if (config.options.delay > 0) { + if (throttleRestartBus === undefined) { + throttleRestartBus = throttle(restartBus, config.options.delay, {trailing:false}); } - - bus.emit('restart', matched.result); - - }, config.options.delay); - return; + return throttleRestartBus(matched); + } + else { + return restartBus(matched); + } } } diff --git a/test/fork/watch-restart.test.js b/test/fork/watch-restart.test.js index 68fd6a6..bc1fcb2 100644 --- a/test/fork/watch-restart.test.js +++ b/test/fork/watch-restart.test.js @@ -5,7 +5,7 @@ var assert = require('assert'), utils = require('../utils'), colour = require('../../lib/utils/colour'), appjs = utils.appjs, - appcoffee = utils.appcoffee, + // appcoffee = utils.appcoffee, run = utils.run, cleanup = utils.cleanup, path = require('path'), @@ -86,6 +86,41 @@ describe('nodemon fork child restart', function () { }); }); + it('should happen only once if delay option is set', function (done) { + var restartCount = 0; + fs.writeFileSync(tmpjs, 'true;'); + + var p = run('--ext js --delay 1' + appjs, { + error: function (data) { + p.send('quit'); + cleanup(p, done, new Error(data)); + } + }); + + p.on('message', function (event) { + if (event.type === 'start') { + setTimeout(function () { + touch.sync(tmpjs); + }, 200); + setTimeout(function () { + touch.sync(tmpjs); + }, 400); + } else if (event.type === 'restart') { + restartCount++; + setTimeout(function () { + if (restartCount===1) { + assert(true, 'nodemon restarted once'); + cleanup(p, done); + } + else { + p.send('quit'); + cleanup(p, done, new Error('nodemon started more than once')); + } + }, 1500); + } + }); + }); + it('should happen when monitoring multiple extensions', function (done) { fs.writeFileSync(tmpjs, 'true;'); fs.writeFileSync(tmpmd, '# true');