.12-浅析webpack源码之NodeWatchFileSystem模块总览

  剩下一个watch模块,这个模块比较深,先大概过一下整体涉及内容再分部讲解。

  流程图如下:

NodeWatchFileSystem

const Watchpack = require("watchpack");class NodeWatchFileSystem {constructor(inputFileSystem) {this.inputFileSystem = inputFileSystem;this.watcherOptions = {aggregateTimeout: 0};this.watcher = new Watchpack(this.watcherOptions);}watch(files, /*Array*/dirs, /*Array*/missing, /*Array*/startTime, /*number*/options, /*object*/callback, /*function*/callbackUndelayed /*function*/) {// params validate...const oldWatcher = this.watcher;// 生成Watchpack对象this.watcher = new Watchpack(options);if (callbackUndelayed)this.watcher.once("change", callbackUndelayed);this.watcher.once("aggregated", (changes, removals) => { /**/ });// 调用watch方法this.watcher.watch(files.concat(missing), dirs.concat(missing), startTime);if (oldWatcher) {oldWatcher.close();}return {close: () => { /**/ },pause: () => { /**/ }};}
}module.exports = NodeWatchFileSystem;

  除去细节代码,该模块大体如下;

1、引入Watchpack模块

2、接受一个inputFileSystem作为构造函数的参数

3、根据配置选项实例化一个Watchpack类

4、核心watch方法为调用实例类的watch方法,传入给定参数,绑定两个一次性事件绑定并返回了一个对象

  模块核心的方法调用的是Watchpack实体类上的,所以需要进一步探究该类。

  该模块涉及到了nodejs的event模块,内容非常简单,这里就不做介绍了,详情可查看官网API:https://nodejs.org/dist/latest-v8.x/docs/api/events.html

 

Watchpack

var watcherManager = require("./watcherManager");
var EventEmitter = require("events").EventEmitter;
Watchpack.prototype = Object.create(EventEmitter.prototype);class Watchpack {constructor(options) {EventEmitter.call(this);if (!options) options = {};if (!options.aggregateTimeout) options.aggregateTimeout = 200;this.options = options;this.watcherOptions = {ignored: options.ignored,poll: options.poll};this.fileWatchers = [];this.dirWatchers = [];this.mtimes = Object.create(null);this.paused = false;this.aggregatedChanges = [];this.aggregatedRemovals = [];this.aggregateTimeout = 0;this._onTimeout = this._onTimeout.bind(this);}watch(files, directories, startTime) {this.paused = false;var oldFileWatchers = this.fileWatchers;var oldDirWatchers = this.dirWatchers;this.fileWatchers = files.map(function(file) {return this._fileWatcher(file, watcherManager.watchFile(file, this.watcherOptions, startTime));}, this);this.dirWatchers = directories.map(function(dir) {return this._dirWatcher(dir, watcherManager.watchDirectory(dir, this.watcherOptions, startTime));}, this);oldFileWatchers.forEach(function(w) {w.close();}, this);oldDirWatchers.forEach(function(w) {w.close();}, this);};pause() { /**/ };getTimes() { /**/ };_fileWatcher(file, watcher) { /**/ };_dirWatcher(item, watcher) { /**/ };_onChange(item, mtime, file) { /**/ };_onRemove(item, file) { /**/ };_onTimeout() { /**/ };close() { /**/ };
}module.exports = Watchpack;function addWatchersToArray(watchers, array) { /**/ }

  本模块引入了并继承了nodejs的EventEmitter,并引入了新模块watcherManager,主要内容罗列如下:

1、构造函数接受一个对象,键包括aggregateTimeout、ignored、poll,本例只传入第一个并设置为0

2、核心方法为watch,依赖于引入的watchManager模块

3、其余方法均为工具方法

 

WatcherManager

var path = require("path");class WatcherManager {constructor() {this.directoryWatchers = {};};// 工厂函数
    getDirectoryWatcher(directory, options) {// 引入模块var DirectoryWatcher = require("./DirectoryWatcher");options = options || {};var key = directory + " " + JSON.stringify(options);if (!this.directoryWatchers[key]) {this.directoryWatchers[key] = new DirectoryWatcher(directory, options);// 文件监视结束则从容器删除this.directoryWatchers[key].on("closed", function() {delete this.directoryWatchers[key];}.bind(this));}return this.directoryWatchers[key];};// 监视文件
    watchFile(p, options, startTime) {var directory = path.dirname(p);return this.getDirectoryWatcher(directory, options).watch(p, startTime);};// 监视目录
    watchDirectory(directory, options, startTime) {return this.getDirectoryWatcher(directory, options).watch(directory, startTime);};
}
module.exports = new WatcherManager();

  可以看出这是一个中间处理函数,其中构造函数生成了一个容器,容器的键为目录+参数生成的一个字符串,当监视关闭后会并立即删除。

  这个模块类似于tapable,是一个监视对象管理器。

 

  然后是监视核心实现模块,模块内容比较多,这里只简单看一下构造函数以及watch方法:

var EventEmitter = require("events").EventEmitter;
var async = require("async");
var chokidar = require("chokidar");
var fs = require("graceful-fs");class Watcher {constructor(directoryWatcher, filePath, startTime) {EventEmitter.call(this);this.directoryWatcher = directoryWatcher;this.path = filePath;this.startTime = startTime && +startTime;this.data = 0;};checkStartTime(mtime, initial) { /**/ };close() { /**/ };
}function DirectoryWatcher(directoryPath, options) {EventEmitter.call(this);this.options = options;this.path = directoryPath;this.files = Object.create(null);this.directories = Object.create(null);this.watcher = chokidar.watch(directoryPath, {ignoreInitial: true,persistent: true,followSymlinks: false,depth: 0,atomic: false,alwaysStat: true,ignorePermissionErrors: true,ignored: options.ignored,usePolling: options.poll ? true : undefined,interval: typeof options.poll === "number" ? options.poll : undefined,disableGlobbing: true});this.watcher.on("add", this.onFileAdded.bind(this));this.watcher.on("addDir", this.onDirectoryAdded.bind(this));this.watcher.on("change", this.onChange.bind(this));this.watcher.on("unlink", this.onFileUnlinked.bind(this));this.watcher.on("unlinkDir", this.onDirectoryUnlinked.bind(this));this.watcher.on("error", this.onWatcherError.bind(this));// ...
}DirectoryWatcher.prototype.watch = function watch(filePath, startTime) {this.watchers[withoutCase(filePath)] = this.watchers[withoutCase(filePath)] || [];this.refs++;var watcher = new Watcher(this, filePath, startTime);watcher.on("closed", function() { /**/ }.bind(this));// ...return watcher;
};// ...

module.exports = DirectoryWatcher;

  从构造函数和模块引入可以得到很多信息,如下:

1、引入了graceful-js模块,可以看出底层还是利用nodejs的fs模块来进行监视

2、所有的监视事件都是基于nodejs的EventEmitter模块来进行操作

3、内部还有一个辅助类Watcher

4、根据构造函数的代码,监视的操作包含(可能不限于)新增文件、新增文件夹、改变内容、删除文件、删除文件夹等

 

  async模块是一个类似于tapable的辅助工具,用于异步处理批量方法,详细内容可自行去网上查阅。

  构造函数中,该模块又再次引用了chokidar模块,并调用其watch方法进行初始化,看似调用方法,源码简化后如下:

class FSWatcher {// ...
}
exports.FSWatcher = FSWatcher;
exports.watch = function(paths, options) {return new FSWatcher(options).add(paths);
};

  假的,这还是个new操作,只是为了方便把两步合成到了一个方法中。

 

  所有的模块整理如上,下面几节再来剖析每一块内容。

转载于:https://www.cnblogs.com/QH-Jimmy/p/8059129.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/453857.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python 第三方模块之 beautifulsoup(bs4)- 解析 HTML

简单来说,Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据。官方解释如下:官网文档 Beautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。 它是一个工具箱,通过解析文档为用户提供…

modal vue 关闭_Vue弹出框的优雅实践

引言页面引用弹出框组件是经常碰见的需求,如果强行将弹出框组件放入到页面中,虽然功能上奏效但没有实现组件与页面间的解耦,非常不利于后期的维护和功能的扩展.下面举个例子来说明一下这种做法的弊端.click"openModal()">点击 :is_open"is_open" close…

开放平台大抉择

开放平台大抉择之新浪SAE:为个人应用开发带来福音 导读:继上期淘宝网副总裁王文彬从平台功能特色、运营状况等多方面分享了淘宝开放平台的历程和挑战之后。国内另一家云平台服务方的典型代表——Sina App Engine(简称SAE),作为新浪研发中心于…

HTTP POST 发送数据的参数 application/x-www-form-urlencoded、multipart/form-data、text/plain

HTTP 简介 HTTP/1.1 协议规定的 HTTP 请求方法有 OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE、CONNECT 这几种。 其中 POST 一般用来向服务端提交数据,本文主要讨论 POST 提交数据的几种方式。 我们知道,HTTP 协议是以 ASCII 码传输,建…

vue 二进制文件的下载(解决乱码和解压报错)

问题描述:项目中使用的是vue框架进行开发,因为文件下载存在权限问题,所以并不能通过 a 链接的 href 属性直接赋值 URL进行下载, (如果你的文件没有下载权限,可以直接通过href属性赋值URL的方法进行文件下载…

浅谈云计算与数据中心计算

文/林仕鼎 云计算概念发端于Google和Amazon等超大规模的互联网公司,随着这些公司业务的成功,作为其支撑技术的云计算也得到了业界的高度认可和广泛传播。时至今日,云计算已被普遍认为是IT产业发展的新阶段,从而被赋予了很多产业和…

数据挖掘:如何寻找相关项

导读:随着大数据时代浪潮的到来数据科学家这一新兴职业也越来越受到人们的关注。本文作者Alexandru Nedelcu就将数学挖掘算法与大数据有机的结合起来,并无缝的应用在面临大数据浪潮的网站之中。 数据科学家需要具备专业领域知识并研究相应的算法以分析对…

00030_ArrayList集合

1、数组可以保存多个元素,但在某些情况下无法确定到底要保存多少个元素,此时数组将不再适用,因为数组的长度不可变 2、JDK中提供了一系列特殊的类,这些类可以存储任意类型的元素,并且长度可变,统称为集合 3…

1.3tf的varible\labelencoder

1.tf的varible变量 import tensorflow as tf #定义变量--这里是计数的变量 statetf.Variable(0,namecounter) print (state.name) #输出变量值 onetf.constant(1) #常量new_valuetf.add(state,one) updatetf.assign(state,new_value)#初始化所有变量 inittf.initialize_all_var…

多线程编程指南

1. 多线程编程指南1--线程基础 线程编程指南1--线程基础 Wednesday, 29. March 2006, 11:48:45 多线程 本文出自:BBS水木清华站 作者:Mccartney (coolcat) (2002-01-29 20:25:25) multithreading可以被翻译成多线程控制。与传统的UNIX不同,一个传统 的UNIX进…

路由器和猫的区别

路由器和猫的区别 网络在我们现在生活中必不可少,我们链接互联网经常需要用到猫和路由器,但是依然有很多菜鸟根本不知道什么是猫什么是路由器,至于猫和路由器怎么使用就更不知道了,下面给大家详细的讲解下路由器和猫的区别。 路由器和猫的用途和链接位置不一样,如下图: 路由器:…

kafka 命令行命令大全

kafka 脚本 connect-distributed.sh connect-mirror-maker.sh connect-standalone.sh kafka-acls.sh kafka-broker-api-versions.sh kafka-configs.sh kafka-console-consumer.sh kafka-console-producer.sh kafka-consumer-groups.sh kafka-consumer-perf-test.sh kafka-dele…

python 第三方模块之 APScheduler - 定时任务

介绍 APScheduler的全称是Advanced Python Scheduler。它是一个轻量级的 Python 定时任务调度框架。APScheduler 支持三种调度任务:固定时间间隔,固定时间点(日期),Linux 下的 Crontab 命令。同时,它还支持…

hadoop分布式搭建

一,前提:下载好虚拟机和安装完毕Ubuntu系统。因为我们配置的是hadoop分布式,所以需要两台虚拟机,一台主机(master),一台从机(slave) 选定一台机器作为 Master 在 Master …

xvid 详解 代码分析 编译等

1. Xvid参数详解 众所周知,Mencoder以其极高的压缩速率和不错的画质赢得了很多朋友的认同! 原来用Mencoder压缩Xvid的AVI都是使用Xvid编码器的默认设置,现在我来给大家冲冲电,讲解一下怎样使用Mencoder命令行高级参数制作Xvid编…

很多人喜欢露脚踝你觉得时尚吗?

当然是 时尚时尚最时尚的 露!****脚!脖!子!image.png人生就是这么奇怪 美容整形可以让你拥有想要的五官 做个手术健个身能让你拥有梦寐的线条 唯独身高这事很难改变(说多了都是泪) 氮素呢 再难也难不倒众位…

深度学习之生成式对抗网络 GAN(Generative Adversarial Networks)

一、GAN介绍 生成式对抗网络GAN(Generative Adversarial Networks)是一种深度学习模型,是近年来复杂分布上无监督学习最具前景的方法之一。它源于2014年发表的论文:《Generative Adversarial Nets》,论文地址&#xf…

深度学习之目标检测:R-CNN、Fast R-CNN、Faster R-CNN

object detection 就是在给定的图片中精确找到物体所在位置,并标注出物体的类别。object detection 要解决的问题就是物体在哪里,是什么这整个流程的问题。然而,这个问题不是容易解决的,物体的尺寸变化范围很大,摆放物…

深度学习之边框回归(Bounding Box Regression)

从rcnn, fast rcnn, faster rcnn, yolo, r-fcn, ssd,到cvpr的yolo9000。这些paper中损失函数都包含了边框回归,除了rcnn详细介绍了,其他的paper都是一笔带过,或者直接引用rcnn就把损失函数写出来了。前三条网上解释比较…

2018 年,React 将独占web前端框架鳌头?

相比 Angular 和 Vue, React 是 2017 年的主要 JS 框架,尤其是 React Native 以前所未有的速度提升自己。 Stateofjs 2017前端框架调查结果 相比较 2016 年的调查结果 所以 ,1 年过去了,Vue.js 显然在前端框架中占据了领导地位&am…