Skip to content

Commit

Permalink
watch: use debounce instead of throttle
Browse files Browse the repository at this point in the history
PR-URL: nodejs#48926
Reviewed-By: Benjamin Gruenbaum <[email protected]>
Reviewed-By: Chemi Atlow <[email protected]>
Reviewed-By: Yagiz Nizipli <[email protected]>
Reviewed-By: Trivikram Kamat <[email protected]>
  • Loading branch information
MoLow authored and rluvaton committed Jul 28, 2023
1 parent 3ee7bf7 commit fb62206
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 16 deletions.
2 changes: 1 addition & 1 deletion lib/internal/main/watch_mode.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const args = ArrayPrototypeFilter(process.execArgv, (arg, i, arr) =>
arg !== '--watch' && arg !== '--watch-preserve-output');
ArrayPrototypePushApply(args, kCommand);

const watcher = new FilesWatcher({ throttle: 500, mode: kShouldFilterModules ? 'filter' : 'all' });
const watcher = new FilesWatcher({ debounce: 500, mode: kShouldFilterModules ? 'filter' : 'all' });
ArrayPrototypeForEach(kWatchedPaths, (p) => watcher.watchPath(p));

let graceTimer;
Expand Down
2 changes: 1 addition & 1 deletion lib/internal/test_runner/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ function runTestFile(path, root, inspectPort, filesWatcher, testNamePatterns) {
function watchFiles(testFiles, root, inspectPort, signal, testNamePatterns) {
const runningProcesses = new SafeMap();
const runningSubtests = new SafeMap();
const watcher = new FilesWatcher({ __proto__: null, throttle: 500, mode: 'filter', signal });
const watcher = new FilesWatcher({ __proto__: null, debounce: 500, mode: 'filter', signal });
const filesWatcher = { __proto__: null, watcher, runningProcesses, runningSubtests };

watcher.on('changed', ({ owners }) => {
Expand Down
20 changes: 11 additions & 9 deletions lib/internal/watch_mode/files_watcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,19 @@ const supportsRecursiveWatching = process.platform === 'win32' ||
class FilesWatcher extends EventEmitter {
#watchers = new SafeMap();
#filteredFiles = new SafeSet();
#throttling = new SafeSet();
#debouncing = new SafeSet();
#depencencyOwners = new SafeMap();
#ownerDependencies = new SafeMap();
#throttle;
#debounce;
#mode;
#signal;

constructor({ throttle = 500, mode = 'filter', signal } = kEmptyObject) {
constructor({ debounce = 500, mode = 'filter', signal } = kEmptyObject) {
super();

validateNumber(throttle, 'options.throttle', 0, TIMEOUT_MAX);
validateNumber(debounce, 'options.debounce', 0, TIMEOUT_MAX);
validateOneOf(mode, 'options.mode', ['filter', 'all']);
this.#throttle = throttle;
this.#debounce = debounce;
this.#mode = mode;
this.#signal = signal;

Expand Down Expand Up @@ -74,16 +74,18 @@ class FilesWatcher extends EventEmitter {
}

#onChange(trigger) {
if (this.#throttling.has(trigger)) {
if (this.#debouncing.has(trigger)) {
return;
}
if (this.#mode === 'filter' && !this.#filteredFiles.has(trigger)) {
return;
}
this.#throttling.add(trigger);
this.#debouncing.add(trigger);
const owners = this.#depencencyOwners.get(trigger);
this.emit('changed', { owners });
setTimeout(() => this.#throttling.delete(trigger), this.#throttle).unref();
setTimeout(() => {
this.#debouncing.delete(trigger);
this.emit('changed', { owners });
}, this.#debounce).unref();
}

get watchedPaths() {
Expand Down
10 changes: 5 additions & 5 deletions test/parallel/test-watch-mode-files_watcher.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ describe('watch mode file watcher', () => {

beforeEach(() => {
changesCount = 0;
watcher = new FilesWatcher({ throttle: 100 });
watcher = new FilesWatcher({ debounce: 100 });
watcher.on('changed', () => changesCount++);
});

Expand All @@ -51,7 +51,7 @@ describe('watch mode file watcher', () => {
assert.strictEqual(changesCount, 1);
});

it('should throttle changes', async () => {
it('should debounce changes', async () => {
const file = path.join(tmpdir.path, 'file2');
writeFileSync(file, 'written');
watcher.filterFile(file);
Expand All @@ -61,7 +61,7 @@ describe('watch mode file watcher', () => {
writeFileSync(file, '2');
writeFileSync(file, '3');
writeFileSync(file, '4');
await setTimeout(200); // throttle * 2
await setTimeout(200); // debounce * 2
writeFileSync(file, '5');
const changed = once(watcher, 'changed');
writeFileSync(file, 'after');
Expand All @@ -86,8 +86,8 @@ describe('watch mode file watcher', () => {
await writeAndWaitForChanges(watcher, file);

writeFileSync(file, '1');
assert.strictEqual(changesCount, 1);

await setTimeout(200); // avoid throttling
watcher.clearFileFilters();
writeFileSync(file, '2');
// Wait for this long to make sure changes are triggered only once
Expand All @@ -97,7 +97,7 @@ describe('watch mode file watcher', () => {

it('should watch all files in watched path when in "all" mode',
{ skip: !supportsRecursiveWatching }, async () => {
watcher = new FilesWatcher({ throttle: 100, mode: 'all' });
watcher = new FilesWatcher({ debounce: 100, mode: 'all' });
watcher.on('changed', () => changesCount++);

const file = path.join(tmpdir.path, 'file5');
Expand Down

0 comments on commit fb62206

Please sign in to comment.