|
|
/*!
|
|
|
* destroy
|
|
|
* Copyright(c) 2014 Jonathan Ong
|
|
|
* Copyright(c) 2015-2022 Douglas Christopher Wilson
|
|
|
* MIT Licensed
|
|
|
*/
|
|
|
|
|
|
'use strict'; // 启用严格模式
|
|
|
|
|
|
/**
|
|
|
* 模块依赖项。
|
|
|
* @private
|
|
|
*/
|
|
|
|
|
|
var EventEmitter = require('events').EventEmitter; // 引入 EventEmitter 类
|
|
|
var ReadStream = require('fs').ReadStream; // 引入文件读取流
|
|
|
var Stream = require('stream'); // 引入流模块
|
|
|
var Zlib = require('zlib'); // 引入 zlib 模块,用于压缩和解压缩流
|
|
|
|
|
|
/**
|
|
|
* 模块导出。
|
|
|
* @public
|
|
|
*/
|
|
|
|
|
|
module.exports = destroy; // 导出 destroy 函数
|
|
|
|
|
|
/**
|
|
|
* 销毁给定的流,并可选择抑制未来的 `error` 事件。
|
|
|
*
|
|
|
* @param {object} stream - 要销毁的流对象。
|
|
|
* @param {boolean} suppress - 是否抑制错误事件。
|
|
|
* @public
|
|
|
*/
|
|
|
|
|
|
function destroy(stream, suppress) {
|
|
|
// 判断流的类型并调用相应的销毁函数
|
|
|
if (isFsReadStream(stream)) {
|
|
|
destroyReadStream(stream); // 如果是文件读取流,调用销毁文件读取流的函数
|
|
|
} else if (isZlibStream(stream)) {
|
|
|
destroyZlibStream(stream); // 如果是 zlib 流,调用销毁 zlib 流的函数
|
|
|
} else if (hasDestroy(stream)) {
|
|
|
stream.destroy(); // 如果流具有 destroy 方法,则直接调用它
|
|
|
}
|
|
|
|
|
|
// 如果流是事件发射器并且 suppress 为 true,移除所有错误事件监听器
|
|
|
if (isEventEmitter(stream) && suppress) {
|
|
|
stream.removeAllListeners('error'); // 移除所有 'error' 事件监听器
|
|
|
stream.addListener('error', noop); // 添加一个空的错误处理函数
|
|
|
}
|
|
|
|
|
|
return stream; // 返回被销毁的流
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 销毁 ReadStream。
|
|
|
*
|
|
|
* @param {object} stream - 要销毁的 ReadStream 对象。
|
|
|
* @private
|
|
|
*/
|
|
|
|
|
|
function destroyReadStream(stream) {
|
|
|
stream.destroy(); // 调用流的 destroy 方法
|
|
|
|
|
|
// 如果流具有 close 方法,添加 'open' 事件的监听器
|
|
|
if (typeof stream.close === 'function') {
|
|
|
// node.js 核心 bug 的解决方法
|
|
|
stream.on('open', onOpenClose); // 在流打开时调用 onOpenClose 函数
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 关闭 Zlib 流。
|
|
|
*
|
|
|
* Zlib 流在 Node.js 4.5.5 之前的实现中,
|
|
|
* 当 zlib 遇到错误时,.close() 方法存在bug。
|
|
|
*
|
|
|
* @param {object} stream - 要关闭的 Zlib 流对象。
|
|
|
* @private
|
|
|
*/
|
|
|
|
|
|
function closeZlibStream(stream) {
|
|
|
// 如果流有错误,处理流的关闭
|
|
|
if (stream._hadError === true) {
|
|
|
var prop = stream._binding === null
|
|
|
? '_binding' // 选择属性
|
|
|
: '_handle';
|
|
|
|
|
|
// 创建一个关闭函数,将属性设置为 null
|
|
|
stream[prop] = {
|
|
|
close: function () { this[prop] = null; }
|
|
|
};
|
|
|
}
|
|
|
|
|
|
stream.close(); // 调用流的 close 方法
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Destroy a Zlib stream.
|
|
|
*
|
|
|
* Zlib streams don't have a destroy function in Node.js 6. On top of that
|
|
|
* simply calling destroy on a zlib stream in Node.js 8+ will result in a
|
|
|
* memory leak. So until that is fixed, we need to call both close AND destroy.
|
|
|
*
|
|
|
* PR to fix memory leak: https://github.com/nodejs/node/pull/23734
|
|
|
*
|
|
|
* In Node.js 6+8, it's important that destroy is called before close as the
|
|
|
* stream would otherwise emit the error 'zlib binding closed'.
|
|
|
*
|
|
|
* @param {object} stream
|
|
|
* @private
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
* 销毁 Zlib 流。
|
|
|
*
|
|
|
* @param {object} stream - 要销毁的 Zlib 流对象。
|
|
|
*/
|
|
|
|
|
|
function destroyZlibStream(stream) {
|
|
|
// 检查流是否具有 destroy 方法
|
|
|
if (typeof stream.destroy === 'function') {
|
|
|
// node.js 核心 bug 的解决方法
|
|
|
// istanbul ignore if: node.js 0.8
|
|
|
if (stream._binding) {
|
|
|
// 处理 Node.js 版本小于 0.10.0 的情况
|
|
|
stream.destroy(); // 调用流的 destroy 方法
|
|
|
|
|
|
// 如果流正在处理数据
|
|
|
if (stream._processing) {
|
|
|
stream._needDrain = true; // 标记需要排空
|
|
|
stream.once('drain', onDrainClearBinding); // 一旦排空,调用 onDrainClearBinding 函数
|
|
|
} else {
|
|
|
stream._binding.clear(); // 清除绑定
|
|
|
}
|
|
|
} else if (stream._destroy && stream._destroy !== Stream.Transform.prototype._destroy) {
|
|
|
// 处理 Node.js 版本大于等于 12,或 11.1.0,或 10.15.1 的情况
|
|
|
stream.destroy(); // 调用流的 destroy 方法
|
|
|
} else if (stream._destroy && typeof stream.close === 'function') {
|
|
|
// 处理 Node.js 版本为 7 或 8 的情况
|
|
|
stream.destroyed = true; // 标记流为已销毁
|
|
|
stream.close(); // 调用流的 close 方法
|
|
|
} else {
|
|
|
// 备用方案
|
|
|
// istanbul ignore next
|
|
|
stream.destroy(); // 调用流的 destroy 方法
|
|
|
}
|
|
|
} else if (typeof stream.close === 'function') {
|
|
|
// 处理 Node.js 版本小于 8 的备用方案
|
|
|
closeZlibStream(stream); // 调用关闭 zlib 流的函数
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 确定流是否具有 destroy 方法。
|
|
|
* @private
|
|
|
*/
|
|
|
|
|
|
function hasDestroy(stream) {
|
|
|
return stream instanceof Stream && // 检查流是否是 Stream 的实例
|
|
|
typeof stream.destroy === 'function'; // 检查流是否具有 destroy 方法
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 确定 val 是否是 EventEmitter。
|
|
|
* @private
|
|
|
*/
|
|
|
|
|
|
function isEventEmitter(val) {
|
|
|
return val instanceof EventEmitter; // 检查 val 是否是 EventEmitter 的实例
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 确定流是否是 fs.ReadStream 流。
|
|
|
* @private
|
|
|
*/
|
|
|
|
|
|
function isFsReadStream(stream) {
|
|
|
return stream instanceof ReadStream; // 检查流是否是 ReadStream 的实例
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 确定流是否是 Zlib 流。
|
|
|
* @private
|
|
|
*/
|
|
|
|
|
|
function isZlibStream(stream) {
|
|
|
// 检查流是否是 Zlib 的不同类型的实例
|
|
|
return stream instanceof Zlib.Gzip ||
|
|
|
stream instanceof Zlib.Gunzip ||
|
|
|
stream instanceof Zlib.Deflate ||
|
|
|
stream instanceof Zlib.DeflateRaw ||
|
|
|
stream instanceof Zlib.Inflate ||
|
|
|
stream instanceof Zlib.InflateRaw ||
|
|
|
stream instanceof Zlib.Unzip;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* No-op function.
|
|
|
* @private
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
* 销毁 Zlib 流。
|
|
|
*
|
|
|
* @param {object} stream - 要销毁的 Zlib 流对象。
|
|
|
*/
|
|
|
|
|
|
function destroyZlibStream(stream) {
|
|
|
// 检查流是否具有 destroy 方法
|
|
|
if (typeof stream.destroy === 'function') {
|
|
|
// node.js 核心 bug 的解决方法
|
|
|
// istanbul ignore if: node.js 0.8
|
|
|
if (stream._binding) {
|
|
|
// 处理 Node.js 版本小于 0.10.0 的情况
|
|
|
stream.destroy(); // 调用流的 destroy 方法
|
|
|
|
|
|
// 如果流正在处理数据
|
|
|
if (stream._processing) {
|
|
|
stream._needDrain = true; // 标记需要排空
|
|
|
stream.once('drain', onDrainClearBinding); // 一旦排空,调用 onDrainClearBinding 函数
|
|
|
} else {
|
|
|
stream._binding.clear(); // 清除绑定
|
|
|
}
|
|
|
} else if (stream._destroy && stream._destroy !== Stream.Transform.prototype._destroy) {
|
|
|
// 处理 Node.js 版本大于等于 12,或 11.1.0,或 10.15.1 的情况
|
|
|
stream.destroy(); // 调用流的 destroy 方法
|
|
|
} else if (stream._destroy && typeof stream.close === 'function') {
|
|
|
// 处理 Node.js 版本为 7 或 8 的情况
|
|
|
stream.destroyed = true; // 标记流为已销毁
|
|
|
stream.close(); // 调用流的 close 方法
|
|
|
} else {
|
|
|
// 备用方案
|
|
|
// istanbul ignore next
|
|
|
stream.destroy(); // 调用流的 destroy 方法
|
|
|
}
|
|
|
} else if (typeof stream.close === 'function') {
|
|
|
// 处理 Node.js 版本小于 8 的备用方案
|
|
|
closeZlibStream(stream); // 调用关闭 zlib 流的函数
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 确定流是否具有 destroy 方法。
|
|
|
* @private
|
|
|
*/
|
|
|
|
|
|
function hasDestroy(stream) {
|
|
|
return stream instanceof Stream && // 检查流是否是 Stream 的实例
|
|
|
typeof stream.destroy === 'function'; // 检查流是否具有 destroy 方法
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 确定 val 是否是 EventEmitter。
|
|
|
* @private
|
|
|
*/
|
|
|
|
|
|
function isEventEmitter(val) {
|
|
|
return val instanceof EventEmitter; // 检查 val 是否是 EventEmitter 的实例
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 确定流是否是 fs.ReadStream 流。
|
|
|
* @private
|
|
|
*/
|
|
|
|
|
|
function isFsReadStream(stream) {
|
|
|
return stream instanceof ReadStream; // 检查流是否是 ReadStream 的实例
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 确定流是否是 Zlib 流。
|
|
|
* @private
|
|
|
*/
|
|
|
|
|
|
function isZlibStream(stream) {
|
|
|
// 检查流是否是 Zlib 的不同类型的实例
|
|
|
return stream instanceof Zlib.Gzip ||
|
|
|
stream instanceof Zlib.Gunzip ||
|
|
|
stream instanceof Zlib.Deflate ||
|
|
|
stream instanceof Zlib.DeflateRaw ||
|
|
|
stream instanceof Zlib.Inflate ||
|
|
|
stream instanceof Zlib.InflateRaw ||
|
|
|
stream instanceof Zlib.Unzip;
|
|
|
}
|