日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

node实现watcher的困境

發布時間:2023/12/19 编程问答 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 node实现watcher的困境 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

  • fs.watch
  • 問題
  • 解決方案
    • 輪訓
    • 手動適配

@(node,watcher)

watcher,在如今的前端領域已經數見不鮮了。目前流行的gulp流程工具提供了watcher的選項,是我們在開發過程中不需要手動進行觸發構建流程,轉而根據文件(目錄)內容改變來觸發。

深入到watcher實現層,其實是基于node的fs.watch API,但是fs.watch有很多“不確定性”,下文會一一解答。


fs.watch

(fs.FSWatcher) fs.watch(filename[, options][, listener])

watch API很簡單,接受三個參數,并返回一個FSWatcher對象。
filename可以是文件,也可是目錄;
options為可選對象,默認為{ persistent: true, recursive: false },其中persistent屬性意味著:watcher進程會一直watch該文件(目錄),即watcher進程阻塞;recursive屬性意味著:如果監聽的是目錄,則目錄下屬的目錄和文件也會被監聽,recursive屬性存在兼容性問題,在linux系統下無效,在windows和OSX下正常。
listener為回調函數,接受兩個參數,分別為event和filename,其中事件有兩種類型,“rename”和“change”,而filename也有兼容性問題,在使用時也要注意兼容性判斷。

問題

在上一節中簡單介紹了watch API,也簡單提到了一些兼容性問題,在此列舉出來:

  • recursive屬性在linux下失效;
  • watch目錄時,回調函數中的filename只在linux和windows下可以獲取;
  • node在任何情況下都不確保filename可以獲取到

解決方案

輪訓

node提供了另一個接口,

fs.watchFile(filename[, options], listener)

返回值同為FSWatcher,參數filename可為目錄和文件,options默認為
{ persistent: true, interval: 5007 },其中interval則為node輪訓該文件的時間間隔,listener接受兩個參數,即類行為fs.Stat的curr和prev對象,我們可通過

curr.mtime == prev.mtime

判斷文件是否發生改動。

不管在何種系統設計中,輪訓的方式都是兼容性保底方案,只要我們的系統支持fs.watch方法,就不用采用該種方式進行兼容。

那么合適可以采用輪訓呢?我認為,大概分兩種情況:

  • 需要針對文件的元信息判斷是否觸發事件
  • 監控的文件所在的操作系統,如果是NFS, SMB等網絡文件系統,fs.watch并不提供功能,因此只能使用輪訓方式(watch方法是基于文件系統的特性編寫的,在linux下基于“inotify”,windows下基于“ReadDirectoryChangesW”)

手動適配

針對非網絡文件系統,watch API的兼容性就在于是否遞歸watch以及OSX下filename獲取的問題,因此我們可以通過編碼方式解決:

  • 采用默認的options配置,即{ persistent: true, recursive: false },通過walker便利目錄,針對單個文件作watcher
  • 針對單個文件做watch,OSX可以獲取到filename

通過簡單的處理,一個簡易的watcher就實現了,配合著EventEmit,就可以通過事件的方式完成watcher任務。

參考代碼:

'use strict';var fs = require('fs'); var path = require('path'); var os = require('os');var watchList = {}; var timer = {};var walk = function (dir, callback, filter) {fs.readdirSync(dir).forEach(function (item) {var fullname = path.join(dir, item);if (fs.statSync(fullname).isDirectory()){if (!filter(fullname)){return;}watch(fullname, callback, filter);walk(fullname, callback, filter);}}); };var watch = function (name, callback, filter) {if (watchList[name]) {watchList[name].close();}watchList[name] = fs.watch(name, function (event, filename) {if (filename === null) {return;}var fullname = path.join(name, filename);var type;var fstype;if (!filter(fullname)) {return;}// 檢查文件、目錄是否存在if (!fs.existsSync(fullname)) {// 如果目錄被刪除則關閉監視器if (watchList[fullname]) {fstype = 'directory';watchList[fullname].close();delete watchList[fullname];} else {fstype = 'file';}type = 'delete';} else {// 文件if (fs.statSync(fullname).isFile()) {fstype = 'file';type = event == 'rename' ? 'create' : 'updated';// 文件夾} else if (event === 'rename') {fstype = 'directory';type = 'create';watch(fullname, callback, filter);walk(fullname, callback, filter);}}var eventData = {type: type,target: filename,parent: parent,fstype: fstype};if (/windows/i.test(os.type())) {// window 下的兼容處理clearTimeout(timer[fullname]);timer[fullname] = setTimeout(function() {callback(eventData);}, 16);} else {callback(eventData);}});};/*** @param {String} 要監聽的目錄* @param {Function} 文件、目錄改變后的回調函數* @param {Function} 過濾器(可選)*/ module.exports = function (dir, callback, filter) {// 排除“.”、“_”開頭或者非英文命名的目錄var FILTER_RE = /[^\w\.\-$]/;filter = filter || function (name) {return !FILTER_RE.test(name);};watch(dir, callback, filter);walk(dir, callback, filter); };

轉載于:https://www.cnblogs.com/accordion/p/5106364.html

總結

以上是生活随笔為你收集整理的node实现watcher的困境的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。