fs: make unwatchFile() remove a specific listener

Before this commit, `fs.unwatchFile(path)` removed *all* listeners for `path`.

The function is overloaded now: `fs.unwatchFile(path)` still removes all
listeners, but `fs.unwatchFile(path, cb)` lets you remove a specific listener.

Fixes #3660.
This commit is contained in:
Ben Noordhuis 2012-07-08 16:31:07 +02:00
parent bf539f9bfd
commit 5b5362aa8d
3 changed files with 53 additions and 11 deletions

View File

@ -461,12 +461,16 @@ These stat objects are instances of `fs.Stat`.
If you want to be notified when the file was modified, not just accessed If you want to be notified when the file was modified, not just accessed
you need to compare `curr.mtime` and `prev.mtime`. you need to compare `curr.mtime` and `prev.mtime`.
## fs.unwatchFile(filename, [listener])
## fs.unwatchFile(filename)
Stability: 2 - Unstable. Use fs.watch instead, if available. Stability: 2 - Unstable. Use fs.watch instead, if available.
Stop watching for changes on `filename`. Stop watching for changes on `filename`. If `listener` is specified, only that
particular listener is removed. Otherwise, *all* listeners are removed and you
have effectively stopped watching `filename`.
Calling `fs.unwatchFile()` with a filename that is not being watched is a
no-op, not an error.
## fs.watch(filename, [options], [listener]) ## fs.watch(filename, [options], [listener])

View File

@ -943,10 +943,18 @@ fs.watchFile = function(filename) {
return stat; return stat;
}; };
fs.unwatchFile = function(filename) { fs.unwatchFile = function(filename, listener) {
var stat; if (!inStatWatchers(filename)) return;
if (inStatWatchers(filename)) {
stat = statWatchers[filename]; var stat = statWatchers[filename];
if (typeof listener === 'function') {
stat.removeListener('change', listener);
} else {
stat.removeAllListeners('change');
}
if (stat.listeners('change').length === 0) {
stat.stop(); stat.stop();
statWatchers[filename] = undefined; statWatchers[filename] = undefined;
} }

View File

@ -26,6 +26,7 @@ var fs = require('fs');
var watchSeenOne = 0; var watchSeenOne = 0;
var watchSeenTwo = 0; var watchSeenTwo = 0;
var watchSeenThree = 0;
var startDir = process.cwd(); var startDir = process.cwd();
var testDir = common.fixturesDir; var testDir = common.fixturesDir;
@ -37,12 +38,16 @@ var filenameTwo = 'hasOwnProperty';
var filepathTwo = filenameTwo; var filepathTwo = filenameTwo;
var filepathTwoAbs = path.join(testDir, filenameTwo); var filepathTwoAbs = path.join(testDir, filenameTwo);
var filenameThree = 'charm'; // because the third time is
process.on('exit', function() { process.on('exit', function() {
fs.unlinkSync(filepathOne); fs.unlinkSync(filepathOne);
fs.unlinkSync(filepathTwoAbs); fs.unlinkSync(filepathTwoAbs);
fs.unlinkSync(filenameThree);
assert.equal(1, watchSeenOne); assert.equal(1, watchSeenOne);
assert.equal(1, watchSeenTwo); assert.equal(2, watchSeenTwo);
assert.equal(1, watchSeenThree);
}); });
@ -86,13 +91,38 @@ assert.throws(
assert.doesNotThrow( assert.doesNotThrow(
function() { function() {
fs.watchFile(filepathTwo, function(curr, prev) { function a(curr, prev) {
fs.unwatchFile(filepathTwo); fs.unwatchFile(filepathTwo, a);
++watchSeenTwo; ++watchSeenTwo;
}); }
function b(curr, prev) {
fs.unwatchFile(filepathTwo, b);
++watchSeenTwo;
}
fs.watchFile(filepathTwo, a);
fs.watchFile(filepathTwo, b);
} }
); );
setTimeout(function() { setTimeout(function() {
fs.writeFileSync(filepathTwoAbs, 'pardner'); fs.writeFileSync(filepathTwoAbs, 'pardner');
}, 1000); }, 1000);
assert.doesNotThrow(
function() {
function a(curr, prev) {
assert.ok(0); // should not run
}
function b(curr, prev) {
fs.unwatchFile(filenameThree, b);
++watchSeenThree;
}
fs.watchFile(filenameThree, a);
fs.watchFile(filenameThree, b);
fs.unwatchFile(filenameThree, a);
}
);
setTimeout(function() {
fs.writeFileSync(filenameThree, 'pardner');
}, 1000);