監(jiān)視文件系統(tǒng)意味著監(jiān)視特定目錄或文件的更改。
有時(shí)您可能需要持續(xù)觀察特定文件或目錄的更改。出于這個(gè)原因,我們使用像 chokidar 這樣的文件系統(tǒng) Watcher 或內(nèi)置的 NodeJs 文件系統(tǒng)方法 fs.watch()。
但是我們不會(huì)使用上面的方法,讓我來告訴你這樣做的原因。
fs.watch()
fs 提供了一個(gè)應(yīng)用程序編程接口 (API),可連續(xù)監(jiān)視文件的更改??梢允褂么朔椒ǜ櫸募?,該方法返回一個(gè) fs.FSWatcher 對象。在這里閱讀更多關(guān)于它的信息 fs.watch()。
缺點(diǎn):
- 這種方法不可靠,每次修改都可能在監(jiān)聽器中顯示多個(gè)事件。
- 將大多數(shù)更改作為重命名發(fā)出。
- 不提供遞歸查看文件樹的簡單方法。
- 不報(bào)告 macOS 上的文件名。
還有很多…
chokidar
它是最流行的文件系統(tǒng)觀察器,但盡管在某些情況下它可能就足夠了,但它并不完美。
優(yōu)點(diǎn):
- 它支持處理符號鏈接。
- 它有一些內(nèi)置支持,可以在執(zhí)行原子寫入時(shí)處理寫入磁盤的臨時(shí)文件,盡管在 Watcher 中忽略它們也很簡單,您可以通過忽略選項(xiàng)忽略它們。
- 它可以更可靠地觀察網(wǎng)絡(luò)連接的路徑,盡管在觀察大量文件時(shí)會(huì)導(dǎo)致性能問題。
- 盡管 Watcher(一個(gè)文件系統(tǒng)觀察程序庫,我們稍后會(huì)討論)具有更全面的測試套件并且也用于生產(chǎn)(例如在 Notable 中,它之前使用了 chokidar),但它經(jīng)過了更多的實(shí)戰(zhàn)測試。
缺點(diǎn):
- 它需要原生依賴才能在 macOS 下進(jìn)行高效的遞歸觀察,而原生依賴可能很難使用。
- 在 windows 下它不能有效地遞歸地觀察,另一方面,Watcher(一個(gè)文件系統(tǒng)觀察器庫,我們將在后面討論)是建立在 Node 的 Windows 原生遞歸觀察能力之上的。
- 它無法檢測重命名。
- 如果您不需要像 globbing 這樣的功能,那么 chokidar 會(huì)不必要地膨脹您的應(yīng)用程序包。
- EMFILE 錯(cuò)誤沒有得到正確處理,因此如果您觀看的文件足夠多,chokidar 最終會(huì)放棄它們。
因?yàn)槊糠N方法都有自己的缺點(diǎn)。現(xiàn)在讓我們來看看解決方案。
Watcher
一個(gè)追求完美的文件系統(tǒng)觀察者,沒有原生依賴和可選的重命名檢測支持。
我自己使用過這個(gè)庫,與其他替代方案相比,我發(fā)現(xiàn)它非常簡單且無錯(cuò)誤。
特征:
- 可靠:該庫旨在處理處理文件系統(tǒng)時(shí)可能出現(xiàn)的所有問題,包括一些最流行的無法處理的替代方案,例如 EMFILE 錯(cuò)誤。
- 重命名檢測:這個(gè)庫可以選擇性地檢測文件和目錄何時(shí)被重命名,這允許您在某些情況下為您的用戶提供更好的體驗(yàn)。
- 性能:在可用時(shí)使用本機(jī)遞歸監(jiān)視(macOS 和 Windows),否則可以有效地手動(dòng)執(zhí)行。
- 沒有原生依賴:原生依賴使用起來會(huì)很痛苦,這個(gè)庫使用了其中的 0 個(gè)。
- 不臃腫:許多替代觀察者附帶可能無用且昂貴的功能,例如對通配的支持,這個(gè)庫旨在更精簡,同時(shí)仍然公開正確的抽象,讓您可以根據(jù)需要使用通配。
- TypeScript-ready:這個(gè)庫是用 TypeScript 編寫的,所以類型不是事后才想到的,而是隨庫一起提供的。
您可以在此處查看與其他觀察者的比較。
安裝:
npm install — save watcher
用法:
你會(huì)像這樣使用這個(gè)庫:
const Wattcher = require('watcher')
// Watching a single path
const watcher = new Watcher ( '/foo/bar' );
// Watching multiple paths
const watcher = new Watcher ( ['/foo/bar', '/baz/qux'] );
// Passing some options
const watcher = new Watcher ( '/foo/bar', { renameDetection: true } );
// Passing an "all" handler directly
const watcher = new Watcher ( '/foo/bar', {}, ( event, targetPath, targetPathNext ) => {} );
// Attaching the "all" handler manually
const watcher = new Watcher ( '/foo/bar' );
watcher.on ( 'all', ( event, targetPath, targetPathNext ) => { // This is what the library does internally when you pass it a handler directly
console.log ( event ); // => could be any target event: 'add', 'addDir', 'change', 'rename', 'renameDir', 'unlink' or 'unlinkDir'
console.log ( targetPath ); // => the file system path where the event took place, this is always provided
console.log ( targetPathNext ); // => the file system path "targetPath" got renamed to, this is only provided on 'rename'/'renameDir' events
});
// Listening to individual events manually
const watcher = new Watcher ( '/foo/bar' );
watcher.on ( 'error', error => {
console.log ( error instanceof Error ); // => true, "Error" instances are always provided on "error"
});
watcher.on ( 'ready', () => {
// The App just finished instantiation and may soon emit some events
});
watcher.on ( 'close', () => {
// The app just stopped watching and will not emit any further events
});
watcher.on ( 'all', ( event, targetPath, targetPathNext ) => {
console.log ( event ); // => could be any target event: 'add', 'addDir', 'change', 'rename', 'renameDir', 'unlink' or 'unlinkDir'
console.log ( targetPath ); // => the file system path where the event took place, this is always provided
console.log ( targetPathNext ); // => the file system path "targetPath" got renamed to, this is only provided on 'rename'/'renameDir' events
});
watcher.on ( 'add', filePath => {
console.log ( filePath ); // "filePath" just got created, or discovered by the watcher if this is an initial event
});
watcher.on ( 'addDir', directoryPath => {
console.log ( filePath ); // "directoryPath" just got created, or discovered by the watcher if this is an initial event
});
watcher.on ( 'change', filePath => {
console.log ( filePath ); // "filePath" just got modified
});
watcher.on ( 'rename', ( filePath, filePathNext ) => {
console.log ( filePath, filePathNext ); // "filePath" got renamed to "filePathNext"
});
watcher.on ( 'renameDir', ( directoryPath, directoryPathNext ) => {
console.log ( directoryPath, directoryPathNext ); // "directoryPath" got renamed to "directoryPathNext"
});
watcher.on ( 'unlink', filePath => {
console.log ( filePath ); // "filePath" got deleted, or at least moved outside the watched tree
});
watcher.on ( 'unlinkDir', directoryPath => {
console.log ( directoryPath ); // "directoryPath" got deleted, or at least moved outside the watched tree
});
// Closing the watcher once you are done with it
watcher.close ();
// Updating watched roots by closing a watcher and opening an updated one
watcher.close ();
watcher = new Watcher ( /* Updated options... */ );
關(guān)注七爪網(wǎng),獲取更多APP/小程序/網(wǎng)站源碼資源!






