Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ var gaze = new Gaze(pattern, options, callback);

* `options` The options object passed in.
* `interval` {integer} Interval to pass to fs.watchFile
* `debounceDelay` {integer} Delay for events called in succession for the same
file/event in milliseconds
* `debounceDelay` {integer} Delay for events called in succession for the same file/event in milliseconds. Default is `500`.
* `debounceImmediate` {boolean} Whether events should be emitted on the leading edge of the wait interval. Default is `true`.
* `mode` {string} Force the watch mode. Either `'auto'` (default), `'watch'` (force native events), or `'poll'` (force stat polling).
* `cwd` {string} The current working directory to base file patterns from. Default is `process.cwd()`.

Expand Down
29 changes: 24 additions & 5 deletions lib/gaze.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ function Gaze (patterns, opts, done) {
opts.mark = true;
opts.interval = opts.interval || 100;
opts.debounceDelay = opts.debounceDelay || 500;
opts.debounceImmediate = opts.debounceImmediate !== false;
opts.cwd = opts.cwd || process.cwd();
this.options = opts;

Expand Down Expand Up @@ -115,18 +116,36 @@ Gaze.prototype.emit = function () {
});
}

// If cached doesnt exist, create a delay before running the next
// then emit the event
function _emit () {
Gaze.super_.prototype.emit.apply(self, args);
Gaze.super_.prototype.emit.apply(self, ['all', e].concat([].slice.call(args, 1)));
}

// debounce
var cache = this._cached[filepath] || [];
if (cache.indexOf(e) === -1) {
// when this event is first seen within the `debounceDelay` window:
// - store event type to detect duplicate events within the
// `debounceDelay` window
// - set a timeout to remove the the filepath when no subsequent
// changes happen during `debounceDelay` window
// - emit the event
helper.objectPush(self._cached, filepath, e);
clearTimeout(timeoutId);
timeoutId = setTimeout(function () {
delete self._cached[filepath];
if (!self.options.debounceImmediate) _emit();
}, this.options.debounceDelay);
if (this.options.debounceImmediate) _emit();
} else {
// when a duplicate event is seen within the `debounceDelay` window:
// - clear the existing timeout
// - set a new timeout to ensure the last event is emitted
clearTimeout(timeoutId);
timeoutId = setTimeout(function () {
delete self._cached[filepath];
_emit();
}, this.options.debounceDelay);
// Emit the event and `all` event
Gaze.super_.prototype.emit.apply(self, args);
Gaze.super_.prototype.emit.apply(self, ['all', e].concat([].slice.call(args, 1)));
}

// Detect if new folder added to trigger for matching files within folder
Expand Down
49 changes: 48 additions & 1 deletion test/watch_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ function cleanUp (done) {
'nested/added.js',
'nested/.tmp',
'nested/sub/added.js',
'edited.js'
].forEach(function (d) {
try {
var p = path.resolve(__dirname, 'fixtures', d);
Expand Down Expand Up @@ -332,11 +333,57 @@ exports.watch = {
this.close();
});
},
debounceTiming: function (test) {
test.expect(1);
gaze('**/*', function (err, watcher) {
var lastContent = '';
watcher.on('all', function (filepath) {
lastContent = fs.readFileSync(path.resolve(__dirname, 'fixtures', 'edited.js')).toString();
});
watcher.on('end', function () {
test.equal(lastContent, '4', 'should catch the last changed event.');
test.done();
});

var count = 0;
var timer = setInterval(function () {
fs.writeFileSync(path.resolve(__dirname, 'fixtures', 'edited.js'), count);
count++;
if (count > 4) {
clearTimeout(timer);
setTimeout(function () { watcher.close(); }, 1000);
}
}, 100);
});
},
debounceImmediate: function (test) {
test.expect(1);
gaze('**/*', { debounceImmediate: false }, function (err, watcher) {
var called = 0;
watcher.on('all', function (filepath) {
called += 1;
});
watcher.on('end', function () {
test.equal(called, 1, 'should only detect one change event.');
test.done();
});

var count = 0;
var timer = setInterval(function () {
fs.writeFileSync(path.resolve(__dirname, 'fixtures', 'edited.js'), count);
count++;
if (count > 4) {
clearTimeout(timer);
setTimeout(function () { watcher.close(); }, 1000);
}
}, 100);
});
}
};

// These tests on Windows trigger the folder of a file added to that folder
// When they shouldn't. So skipping them for now ;-;
if (process.platform === 'win32') {
delete exports.watch['mkdirThenAddFile'];
delete exports.watch['mkdirThenAddFileWithGruntFileWrite'];
}
}