From ef5ee96129fc447598dd543256d5860a99f748f6 Mon Sep 17 00:00:00 2001 From: Edgar Hipp Date: Mon, 5 Jan 2015 15:48:14 +0100 Subject: [PATCH 1/5] changed --delay option: it now works like a throttle instead of with setTimeout. This changes the behaviour of the option --delay n This means that as soon as one file changes, nodemon will restart the script. The previous behavior was to wait for n seconds before restarting the process. With throttle, the function gets called when the first file changes. After that, all file changes in the interval [t,t+n] are ignored --- lib/monitor/watch.js | 69 ++++++++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 18 deletions(-) diff --git a/lib/monitor/watch.js b/lib/monitor/watch.js index 799b7fd..b485225 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) { @@ -216,24 +261,12 @@ function filterAndRestart(files) { // reset the last check so we're only looking at recently modified 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 (throttleRestartBus===undefined) + { + throttleRestartBus=throttle(restartBus,config.options.delay); } - - bus.emit('restart', matched.result); - - }, config.options.delay); - return; + if (matched.result.length) { + return throttleRestartBus(matched); } } From 986ef40c2945be244579a10ce7df9598785455d9 Mon Sep 17 00:00:00 2001 From: Edgar Hipp Date: Mon, 5 Jan 2015 17:15:47 +0100 Subject: [PATCH 2/5] added trailing: false to throttle If trailing is not set to false, a setTimeOut is called if you call the function when it is 'locked', so you need to set trailing to false to avoid that unnecessary call --- lib/monitor/watch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/monitor/watch.js b/lib/monitor/watch.js index b485225..22b1512 100644 --- a/lib/monitor/watch.js +++ b/lib/monitor/watch.js @@ -263,7 +263,7 @@ function filterAndRestart(files) { if (throttleRestartBus===undefined) { - throttleRestartBus=throttle(restartBus,config.options.delay); + throttleRestartBus=throttle(restartBus,config.options.delay,{trailing:false}); } if (matched.result.length) { return throttleRestartBus(matched); From e31a514cabf502ec5c745b970a6547b9c0b4e390 Mon Sep 17 00:00:00 2001 From: Edgar Hipp Date: Tue, 6 Jan 2015 10:48:06 +0100 Subject: [PATCH 3/5] added test for delay option --- test/fork/watch-restart.test.js | 38 +++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/test/fork/watch-restart.test.js b/test/fork/watch-restart.test.js index 68fd6a6..e36ffac 100644 --- a/test/fork/watch-restart.test.js +++ b/test/fork/watch-restart.test.js @@ -86,6 +86,44 @@ 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'); From 5b3fb19ffe2f399751b41a89519ecf1cb2411c36 Mon Sep 17 00:00:00 2001 From: Edgar Hipp Date: Tue, 6 Jan 2015 10:56:58 +0100 Subject: [PATCH 4/5] using throttle only if config.options.delay>0 --- lib/monitor/watch.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/monitor/watch.js b/lib/monitor/watch.js index 22b1512..450f005 100644 --- a/lib/monitor/watch.js +++ b/lib/monitor/watch.js @@ -261,12 +261,18 @@ function filterAndRestart(files) { // reset the last check so we're only looking at recently modified files config.lastStarted = Date.now(); - if (throttleRestartBus===undefined) - { - throttleRestartBus=throttle(restartBus,config.options.delay,{trailing:false}); - } if (matched.result.length) { - return throttleRestartBus(matched); + if (config.options.delay>0) + { + if (throttleRestartBus===undefined) + { + throttleRestartBus=throttle(restartBus,config.options.delay,{trailing:false}); + } + return throttleRestartBus(matched); + } + else { + return restartBus(matched); + } } } From 308f71ac3a1b7e13c7ad77b0663fbeba773ad0c9 Mon Sep 17 00:00:00 2001 From: Edgar Hipp Date: Tue, 6 Jan 2015 12:23:08 +0100 Subject: [PATCH 5/5] updating files to match nodemons syntax style --- lib/monitor/watch.js | 16 +++++++--------- test/fork/watch-restart.test.js | 25 +++++++++++-------------- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/lib/monitor/watch.js b/lib/monitor/watch.js index 450f005..4edc027 100644 --- a/lib/monitor/watch.js +++ b/lib/monitor/watch.js @@ -262,16 +262,14 @@ function filterAndRestart(files) { config.lastStarted = Date.now(); if (matched.result.length) { - if (config.options.delay>0) - { - if (throttleRestartBus===undefined) - { - throttleRestartBus=throttle(restartBus,config.options.delay,{trailing:false}); - } - return throttleRestartBus(matched); - } + if (config.options.delay > 0) { + if (throttleRestartBus === undefined) { + throttleRestartBus = throttle(restartBus, config.options.delay, {trailing:false}); + } + return throttleRestartBus(matched); + } else { - return restartBus(matched); + return restartBus(matched); } } } diff --git a/test/fork/watch-restart.test.js b/test/fork/watch-restart.test.js index e36ffac..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'), @@ -87,10 +87,9 @@ describe('nodemon fork child restart', function () { }); it('should happen only once if delay option is set', function (done) { - - var restartCount=0; - + var restartCount = 0; fs.writeFileSync(tmpjs, 'true;'); + var p = run('--ext js --delay 1' + appjs, { error: function (data) { p.send('quit'); @@ -109,16 +108,14 @@ describe('nodemon fork child restart', function () { } 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')); - } + 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); } });