跳到主要内容

为什么使用 Pump?

在使用 Node.js 流的 pipe 时,错误不会通过管道流向前传播,如果目标流关闭,源流也不会关闭。pump 模块规范化了这些问题,并在回调中将错误传递给你。

常见的 gulpfile 示例

gulp 文件中的一种常见模式是简单地返回一个 Node.js 流,并期望 gulp 工具处理错误。

// 常见的 gulpfile 示例
var gulp = require('gulp');
var uglify = require('gulp-uglify');

gulp.task('compress', function () {
// 返回一个 Node.js 流,但没有错误消息处理
return gulp.src('lib/*.js')
.pipe(uglify())
.pipe(gulp.dest('dist'));
});

pipe 错误

JavaScript 文件中有一个错误,但错误消息完全没有帮助。你想知道哪个文件和哪一行包含错误。那么这一团乱码是什么?

当流中出现错误时,Node.js 流会触发 'error' 事件,但如果没有这个事件的处理程序,它会转而使用定义的未捕获异常处理程序。未捕获异常处理程序的默认行为已有文档说明:

默认情况下,Node.js 通过将堆栈跟踪打印到 stderr 并退出来处理此类异常。

处理错误

由于让错误到达未捕获的异常处理程序没有用,我们应该正确处理异常。让我们快速尝试一下。

var gulp = require('gulp');
var uglify = require('gulp-uglify');

gulp.task('compress', function () {
return gulp.src('lib/*.js')
.pipe(uglify())
.pipe(gulp.dest('dist'))
.on('error', function(err) {
console.error('压缩任务中的错误', err.toString());
});
});

不幸的是,Node.js 流的 pipe 函数不会将错误转发到链中,所以这个错误处理程序只处理 gulp.dest 给出的错误。相反,我们需要为每个流处理错误。

var gulp = require('gulp');
var uglify = require('gulp-uglify');

gulp.task('compress', function () {
function createErrorHandler(name) {
return function (err) {
console.error('压缩任务中 ' + name + ' 的错误', err.toString());
};
}

return gulp.src('lib/*.js')
.on('error', createErrorHandler('gulp.src'))
.pipe(uglify())
.on('error', createErrorHandler('uglify'))
.pipe(gulp.dest('dist'))
.on('error', createErrorHandler('gulp.dest'));
});

在每个 gulp 任务中添加这么多复杂性很麻烦,而且很容易忘记这样做。此外,这仍然不完美,因为它没有正确地向 gulp 的任务系统发出任务失败的信号。我们可以修复这个问题,并处理流错误传播的其他棘手问题,但这需要更多的工作!

使用 pump

pump 模块是一种作弊码。它是 pipe 功能的包装器,可以为你处理这些情况,这样你就可以停止修改 gulpfile,回去为你的应用开发新功能。

var gulp = require('gulp');
var uglify = require('gulp-uglify');
var pump = require('pump');

gulp.task('compress', function (cb) {
pump([
gulp.src('lib/*.js'),
uglify(),
gulp.dest('dist')
],
cb
);
});

gulp 任务系统为 gulp 任务提供了一个回调,它可以发出任务成功完成的信号(不带参数调用),或任务失败的信号(用 Error 参数调用)。幸运的是,这与 pump 使用的格式完全相同!

pump 错误

现在可以非常清楚地知道错误来自哪个插件,实际错误是什么,以及来自哪个文件和行号。