.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…

Python 第三方模块之 lxml - 解析 HTML 和 XML 文件

lxml是python的一个解析库,支持HTML和XML的解析,支持XPath解析方式,而且解析效率非常高 XPath,全称XML Path Language,即XML路径语言,它是一门在XML文档中查找信息的语言,它最初是用来搜寻XML文…

(转)Linux下PS1、PS2、PS3、PS4使用详解

Linux下PS1、PS2、PS3、PS4使用详解 原文:http://www.linuxidc.com/Linux/2016-10/136597.htm 1、PS1——默认提示符 如下所示,可以通过修改Linux下的默认提示符,使其更加实用。在下面的例子中,默认的PS1的值是“\s-\v\$”,显示出…

开放平台大抉择

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

ip68级防水可以泡多久_iPhone8防水级别升级至IP68:能在1.5米深水中坚持30分钟

1月15日,业界最新的泄密消息显示,苹果拟在今年推出的“iPhone 8”智能手机会是一款革命性的手机,功能和配置就不多说了。苹果还将解决iPhone 7的一个重要缺陷,就是大大增强iPhone 8的防水性能,防水级别达IP68。《韩国先…

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的方法进行文件下载…

Python 第三方模块之 psutil - 获取系统运行的进程和系统利用率信息

一、psutil模块: 官方网址:http://pythonhosted.org/psutil/ 1.psutil是一个跨平台库(http://pythonhosted.org/psutil/)能够轻松实现获取系统运行的进程和系统利用率(包括CPU、内存、磁盘、网络等)信息。它主要用来做系统监控,…

石头机器人红灯快闪_机器人集体“快闪”活动爆红网络 “我是AI”与您相约智能新时代...

原标题:机器人集体“快闪”活动爆红网络 “我是AI”与您相约智能新时代3月10日下午,天津科学技术馆内,悠扬美妙的歌声《我和我的祖国》突然响起,随后50个身形矫健的阿尔法机器人伴随着歌声翩翩起舞,动作整齐、科技感十…

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

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

无线网络实体图生成工具airgraph-ng

无线网络实体图生成工具airgraph-ngairgraph-ng是aircrack-ng套件提供的一个图表生成工具。该工具可以根据airodump工具生成的CSV文件绘制PNG格式的图。绘制的图有两种类型,分别为AP-客户端关联图和通用探测图。通过AP-客户端关联图,可以更为直观的了解无…

高等代数期末考试题库及答案_数学类高等代数期末考试试题A卷(含答案)

数学类高等代数期末考试试题A卷(含答案)课程编号MTH17063 北京理工大学2010-2011学年第一学期2009级数学类高等代数期末考试试题A卷班级 学号 姓名 成绩 一、(25分)设表示域上的所有阶矩阵构成的上的线性空间。取定,对于任意的,定义。(1)证明为上的一个线…

cocos2d-lua3.7组件篇(三)-http通信demo

客户端使用lua、服务端使用QT做为服务器。 步骤: 客户端 -----------Post 用户名和密码 服务端接受Post请求,读取数据,返回response一、客户端代码 loadingImg require"app.scenes.LoadingLayer"local LoginScene class(&qu…

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

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

Python 第三方模块之 selenium - 模拟操作 Chrome 浏览器

1、安装selenium 1.1、Python 安装 selenium 模块 pip install selenium1.2、下载驱动 选择和自己chrom版本相对应的驱动到本地,下载地址 http://npm.taobao.org/mirrors/chromedriver/2、Python 操作 from selenium import webdriver import time import json…

jupyter notebook代码导出_Jupyter Notebook导出包含中文的pdf_亲测有效

Jupyter Notebook是很好的数据科学创作环境,是非常方便的Python代码编辑器。jupyter提供导出的格式有.py、.html、.md、.pdf等。目前用其导出包含中文的pdf会遇到很多坑,网上也有一些解决方案,大致分为两种方式,一是安装 pandoc并…

前端之使用 POST 提交数据并跳转

GET 方式 window.location.href是我们常用来在js中实现页面跳转的方法,这是使用get方式发送请求,示例如下 window.location.href url;优点是简单易用,缺点是如果有参数的话,参数会暴露在url地址中,这降低了系统的安…

cef js返回c++的代码_CEF3开发者系列之外篇——IE中JS与C++交互

使用IE内核开发客户端产品,系统和前端页面之间的交互,通常给开发和维护带来很大的便利性。但操作系统和前端之间的交互却是比较复杂的。具体来说就是脚本语言和编译语言的交互。在IE内核中html和css虽然不兼容,但是IE编程接口是完全一样的,这得益于微软的…

多线程编程指南 part 2

多线程编程指南Sun Microsystems, Inc.4150 Network CircleSanta Clara, CA95054U.S.A.文件号码819–7051–102006 年10 月版权所有2005 Sun Microsystems, Inc. 4150 Network Circle, Santa Clara, CA95054 U.S.A. 保留所有权利。本文档及其相关产品的使用、复制、分发和反编译…