From 5b5362aa8d80d0822f37e2448d024452dd3c0a98 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 8 Jul 2012 16:31:07 +0200 Subject: [PATCH] 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. --- doc/api/fs.markdown | 10 +++++--- lib/fs.js | 16 +++++++++---- test/pummel/test-fs-watch-file.js | 38 +++++++++++++++++++++++++++---- 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/doc/api/fs.markdown b/doc/api/fs.markdown index 4c97a179439..8f801e6ef49 100644 --- a/doc/api/fs.markdown +++ b/doc/api/fs.markdown @@ -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 you need to compare `curr.mtime` and `prev.mtime`. - -## fs.unwatchFile(filename) +## fs.unwatchFile(filename, [listener]) 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]) diff --git a/lib/fs.js b/lib/fs.js index 7c622375e3a..ae9cdf4c4d8 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -943,10 +943,18 @@ fs.watchFile = function(filename) { return stat; }; -fs.unwatchFile = function(filename) { - var stat; - if (inStatWatchers(filename)) { - stat = statWatchers[filename]; +fs.unwatchFile = function(filename, listener) { + if (!inStatWatchers(filename)) return; + + var stat = statWatchers[filename]; + + if (typeof listener === 'function') { + stat.removeListener('change', listener); + } else { + stat.removeAllListeners('change'); + } + + if (stat.listeners('change').length === 0) { stat.stop(); statWatchers[filename] = undefined; } diff --git a/test/pummel/test-fs-watch-file.js b/test/pummel/test-fs-watch-file.js index 3df28af56fc..f3c5f5bb6a4 100644 --- a/test/pummel/test-fs-watch-file.js +++ b/test/pummel/test-fs-watch-file.js @@ -26,6 +26,7 @@ var fs = require('fs'); var watchSeenOne = 0; var watchSeenTwo = 0; +var watchSeenThree = 0; var startDir = process.cwd(); var testDir = common.fixturesDir; @@ -37,12 +38,16 @@ var filenameTwo = 'hasOwnProperty'; var filepathTwo = filenameTwo; var filepathTwoAbs = path.join(testDir, filenameTwo); +var filenameThree = 'charm'; // because the third time is + process.on('exit', function() { fs.unlinkSync(filepathOne); fs.unlinkSync(filepathTwoAbs); + fs.unlinkSync(filenameThree); assert.equal(1, watchSeenOne); - assert.equal(1, watchSeenTwo); + assert.equal(2, watchSeenTwo); + assert.equal(1, watchSeenThree); }); @@ -86,13 +91,38 @@ assert.throws( assert.doesNotThrow( function() { - fs.watchFile(filepathTwo, function(curr, prev) { - fs.unwatchFile(filepathTwo); + function a(curr, prev) { + fs.unwatchFile(filepathTwo, a); ++watchSeenTwo; - }); + } + function b(curr, prev) { + fs.unwatchFile(filepathTwo, b); + ++watchSeenTwo; + } + fs.watchFile(filepathTwo, a); + fs.watchFile(filepathTwo, b); } ); setTimeout(function() { fs.writeFileSync(filepathTwoAbs, 'pardner'); }, 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);