视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
node.js监听文件变化的实现方法
2020-11-27 21:58:36 责编:小采
文档



可以看到1、2两步,并没有实际修改内容,然而我们并没有办法区分。只要你是切换之后再保存,修改时间戳mtime就发生变化。

另外响应时间真的很慢,毕竟是轮询。

对于这些问题,其实官网也给了一句话:

Using fs.watch() is more efficient than fs.watchFile and fs.unwatchFile. fs.watch should be used instead of fs.watchFile and fs.unwatchFile when possible.

能用fs.watch的情况就不要用watchFile了。一是效率,二是不能准确获知修改状态 三是只能监听单独文件
对于实际开发过程中,显然我们想要关注的是源文件夹的变动。

fs.watch

首先用法如下:

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

跟fs.watchFile比较类似。

  • filename 显然就是文件名
  • options 可选 对象或者字符串 包含以下三个属性
  • persistent 文件被监听时进程是否继续,默认true
  • recursive 是否监控所有子目录,默认false 即当前目录,true为所有子目录。
  • encoding 指定传递给回调事件的文件名称,默认utf8
  • listener 事件回调 包含两个参数
  • eventType 事件类型,rename 或者 change
  • filename 当前变更文件的文件名
  • options如果是字符串,指的是encoding。

    监听filename对应的文件或者文件夹(recursive参数也体现出来这一特性),返回一个fs.FSWatcher对象。

    该功能的实现依赖于底层操作系统的对于文件更改的通知。 所以就存在一个问题,可能不同平台的实现不太相同。
    如下示例1:

    const fs = require('fs')
    const filePath = './' 
    console.log(`正在监听 ${filePath}`);
    fs.watch(filePath,(event,filename)=>{
     if (filename){
     console.log(`${filename}文件发生更新`)
     }
    })

    一个比较明显的优势就体现出来了:响应比较及时,相比于轮询,效率肯定更高。

    不过这样修改并保存的时候回发现同样有点问题。

    直接保存,显示两次更新

    修改文件之后,同样显示两次更新(mac系统上是两次,其他系统可能有所差别)

    这样可能是于操作系统对文件修改的事件支持有关,在保存的时候出发了不止一次。

    下面聚焦于回调事件的参数,event对应事件类型,是否可以判断事件类型为change呢,才执行呢,忽略空保存。

    const fs = require('fs')
    const filePath = './' 
    console.log(`正在监听 ${filePath}`);
    fs.watch(filePath,(event,filename)=>{
     console.log(`event类型${event}`)
     if (filename && event == 'change') {
     console.log(`${filename}文件发生更新`)
     }
    })

    不过实际上,空的保存event也是change,另外不同平台event的实现可能也有所不同。这种方式要pass掉。

    校验变更时间

    显然从上面的例子可以看到,变更时间依然不可控。因为每次保存,node对应stat对象依然会修改。

    对比文件内容

    只能选择这种方式来判断是否是否更新。例如md5:

    const fs = require('fs'),
     md5 = require('md5');
    const filePath = './' 
    let preveMd5 = null
    
    console.log(`正在监听 ${filePath}`);
    fs.watch(filePath,(event,filename)=>{
     var currentMd5 = md5(fs.readFileSync(filePath + filename))
     if (currentMd5 == preveMd5) {
     return
     }
     preveMd5 = currentMd5
     console.log(`${filePath}文件发生更新`)
    })

    先保存当前文件md5值,每次文件变化时(即保存操作响应之后),每次都获取文件的md5然后进行对比,看是否发生变化。

    不过这样可以看到,当初次保存时,都会执行一次,因为初始值为null的缘故。这样可以加个兼容,根据是否第一次保存来判断好了。

    优化

    对于不同的操作系统,可能保存时触发的回调不止一个(mac上到没出现)。为了避免这种实时响应对应的频繁触发,可以引入debounce函数来保证性能。

    const fs = require('fs'),
     md5 = require('md5');
    let preveMd5 = null,
     fsWait = false
    const filePath = './' 
    console.log(`正在监听 ${filePath}`);
    fs.watch(filePath,(event,filename)=>{
     if (filename){
     if (fsWait) return;
     fsWait = setTimeout(() => {
     fsWait = false;
     }, 100)
     var currentMd5 = md5(fs.readFileSync(filePath + filename))
     if (currentMd5 == preveMd5){
     return 
     }
     preveMd5 = currentMd5
     console.log(`${filePath}文件发生更新`)
     }
    })

    结束语

    到这里,node监听文件的实现就结束了。做个学习笔记,来做个参考记录。实现起来并不难,但是要实际应用的话需要考虑的方面就比较多了。还是推荐开源框架node-watch、chokidar等,各方面实现的都比较完善。

    好了,

    下载本文
    显示全文
    专题