Async.js 与 Gulp 轮流错误 "Callback was already called"
Async.js with Gulp turns error "Callback was already called"
我正在使用 async.js 以某种有序顺序加载我的 gulp 任务,所以我这样做:
// Gulp Default Build Task
gulp.task('default', function() {
var tasks = ['sass_dev', 'browserify', 'lint', 'watch'];
var sync = tasks.map(function(task) {
return function(callback) {
gulp.start(task, function(err) {
if (err || task.length === 0) {
callback(err);
} else {
callback(null, task[0]);
}
});
};
});
async.series(sync);
});
任务 运行 正确,但在第一次更改脚本后我遇到了一个错误 if (fn === null) throw new Error("Callback was already called.");
。我知道那是因为它调用了两次回调,但即使在 err
条件下它也无法正常工作。有人可以帮忙吗?
有一个更简单的方法。
'use strict';
let gulp = require('gulp');
let concat = require('gulp-concat');
let minifyCSS = require('gulp-minify-css');
let browserify = require('browserify');
let vsource = require("vinyl-source-stream");
let babel = require('babelify');
let source = {
appjs: './ui-src/app.js',
js: ['./ui-src/**/*.js'],
libjs: ['./ui-src/lib/primus/primus.js'],
appcss: ['./ui-src/css/*.css'],
apphtml: ['./ui-src/**/*.html'],
appimg: ['./ui-src/img/*']
};
gulp.task('appjs', function(){
browserify({ debug: true })
.transform(babel.configure({stage: 0}))
.require(source.appjs, { entry: true })
.bundle()
.pipe(vsource('app.min.js'))
.pipe(gulp.dest('./ui-dist'));
});
gulp.task('libjs', function () {
gulp.src(source.libjs)
.pipe(concat('lib.min.js'))
.pipe(gulp.dest('./ui-dist'))
});
gulp.task('appcss', function () {
gulp.src(source.appcss)
.pipe(concat('app.min.css'))
.pipe(minifyCSS())
.pipe(gulp.dest('./ui-dist'))
});
gulp.task('apphtml', function() {
gulp.src(source.apphtml)
.pipe(gulp.dest('./ui-dist'));
gulp.src(source.appimg, {base: 'ui-src'})
.pipe(gulp.dest('./ui-dist'));
});
gulp.task('watch', function() {
gulp.watch(source.appcss, ['appcss']);
gulp.watch(source.apphtml, ['apphtml']);
gulp.watch(source.js, ['appjs']);
});
gulp.task('default', ['appjs', 'appcss', 'apphtml', 'watch']);
gulp.task('nw', ['appjs', 'libjs', 'appcss', 'apphtml']);
问题
您 运行 陷入此问题的原因是您正在使用 Gulp 的一部分,这实际上不是 Gulp 的最终用户使用的。这是一个重现您报告的行为的小 gulpfile:
var gulp = require("gulp");
gulp.task('foo');
gulp.task('default', function () {
gulp.start('foo', function () {
console.log("callback!");
});
setTimeout(function () {
gulp.start('foo');
}, 1000);
});
运行 这将在控制台上产生:
[12:23:48] Using gulpfile /tmp/t15/test.js
[12:23:48] Starting 'default'...
[12:23:48] Starting 'foo'...
[12:23:48] Finished 'foo' after 66 μs
[12:23:48] Finished 'default' after 1.24 ms
callback!
[12:23:49] Starting 'foo'...
[12:23:49] Finished 'foo' after 8.99 μs
callback!
你看到 callback!
出现了两次,尽管 gulp.start
只用回调调用了一次!问题是 Gulp 记住回调并在 gulp.start
的第二次调用中使用它。
如果您想要详细信息,请查看 orchestrator,这是 Gulp 使用的内容。查找 doneCallback
及其管理方式。基本行为是,如果 start
被回调调用,那么它会删除 doneCallback
的任何先前值,但如果它没有被回调调用,那么旧值将保持不变并实际上被重用通过随后调用 start
.
安全的解决方案
总之。看来您想 运行 按顺序执行一堆任务。我过去这样做的方法是声明将按顺序 运行 其他任务的任务,以便:
它的依赖关系是顺序运行任务的所有依赖关系的并集。
它的实现函数依次运行调用它应该执行的所有任务的实现函数
这是一个简短的例子:
var gulp = require("gulp");
gulp.task('x');
gulp.task('y');
gulp.task('q');
// We are defining task `a`, with dependencies `x` and `y`.
var a_deps = ['x', 'y'];
function a() {
console.log("a");
}
gulp.task('a', a_deps);
// We are defining task `b`, with dependencies `x` and `q`.
var b_deps = ['x', 'q'];
function b() {
console.log("b");
}
gulp.task('b', b_deps);
// We are defining task `default`, which is equivalent to running tasks
// `a` and `b` in sequence.
gulp.task('default', a_deps.concat(b_deps), function () {
a();
b();
});
郑重声明,我没有使用 run-sequence
,因为当我尝试它时,我看到它 运行 多次绑定我的依赖项,这对我来说是无法接受的。
当 Gulp 4 出来时,我们将能够使用 gulp.series
对任务进行排序
实际上我使用了其他更轻量级的库 run-sequence
,它运行良好且流畅。所以这是示例解决方案:
var sequence = require('run-sequence');
gulp.task('default', function(callback) {
sequence('sass_dev', ['browserify', 'lint'], 'watch', callback);
});
gulp.task('prod', function(callback) {
sequence('sass_dev', ['browserify'], 'uglify', callback);
});
我正在使用 async.js 以某种有序顺序加载我的 gulp 任务,所以我这样做:
// Gulp Default Build Task
gulp.task('default', function() {
var tasks = ['sass_dev', 'browserify', 'lint', 'watch'];
var sync = tasks.map(function(task) {
return function(callback) {
gulp.start(task, function(err) {
if (err || task.length === 0) {
callback(err);
} else {
callback(null, task[0]);
}
});
};
});
async.series(sync);
});
任务 运行 正确,但在第一次更改脚本后我遇到了一个错误 if (fn === null) throw new Error("Callback was already called.");
。我知道那是因为它调用了两次回调,但即使在 err
条件下它也无法正常工作。有人可以帮忙吗?
有一个更简单的方法。
'use strict';
let gulp = require('gulp');
let concat = require('gulp-concat');
let minifyCSS = require('gulp-minify-css');
let browserify = require('browserify');
let vsource = require("vinyl-source-stream");
let babel = require('babelify');
let source = {
appjs: './ui-src/app.js',
js: ['./ui-src/**/*.js'],
libjs: ['./ui-src/lib/primus/primus.js'],
appcss: ['./ui-src/css/*.css'],
apphtml: ['./ui-src/**/*.html'],
appimg: ['./ui-src/img/*']
};
gulp.task('appjs', function(){
browserify({ debug: true })
.transform(babel.configure({stage: 0}))
.require(source.appjs, { entry: true })
.bundle()
.pipe(vsource('app.min.js'))
.pipe(gulp.dest('./ui-dist'));
});
gulp.task('libjs', function () {
gulp.src(source.libjs)
.pipe(concat('lib.min.js'))
.pipe(gulp.dest('./ui-dist'))
});
gulp.task('appcss', function () {
gulp.src(source.appcss)
.pipe(concat('app.min.css'))
.pipe(minifyCSS())
.pipe(gulp.dest('./ui-dist'))
});
gulp.task('apphtml', function() {
gulp.src(source.apphtml)
.pipe(gulp.dest('./ui-dist'));
gulp.src(source.appimg, {base: 'ui-src'})
.pipe(gulp.dest('./ui-dist'));
});
gulp.task('watch', function() {
gulp.watch(source.appcss, ['appcss']);
gulp.watch(source.apphtml, ['apphtml']);
gulp.watch(source.js, ['appjs']);
});
gulp.task('default', ['appjs', 'appcss', 'apphtml', 'watch']);
gulp.task('nw', ['appjs', 'libjs', 'appcss', 'apphtml']);
问题
您 运行 陷入此问题的原因是您正在使用 Gulp 的一部分,这实际上不是 Gulp 的最终用户使用的。这是一个重现您报告的行为的小 gulpfile:
var gulp = require("gulp");
gulp.task('foo');
gulp.task('default', function () {
gulp.start('foo', function () {
console.log("callback!");
});
setTimeout(function () {
gulp.start('foo');
}, 1000);
});
运行 这将在控制台上产生:
[12:23:48] Using gulpfile /tmp/t15/test.js
[12:23:48] Starting 'default'...
[12:23:48] Starting 'foo'...
[12:23:48] Finished 'foo' after 66 μs
[12:23:48] Finished 'default' after 1.24 ms
callback!
[12:23:49] Starting 'foo'...
[12:23:49] Finished 'foo' after 8.99 μs
callback!
你看到 callback!
出现了两次,尽管 gulp.start
只用回调调用了一次!问题是 Gulp 记住回调并在 gulp.start
的第二次调用中使用它。
如果您想要详细信息,请查看 orchestrator,这是 Gulp 使用的内容。查找 doneCallback
及其管理方式。基本行为是,如果 start
被回调调用,那么它会删除 doneCallback
的任何先前值,但如果它没有被回调调用,那么旧值将保持不变并实际上被重用通过随后调用 start
.
安全的解决方案
总之。看来您想 运行 按顺序执行一堆任务。我过去这样做的方法是声明将按顺序 运行 其他任务的任务,以便:
它的依赖关系是顺序运行任务的所有依赖关系的并集。
它的实现函数依次运行调用它应该执行的所有任务的实现函数
这是一个简短的例子:
var gulp = require("gulp");
gulp.task('x');
gulp.task('y');
gulp.task('q');
// We are defining task `a`, with dependencies `x` and `y`.
var a_deps = ['x', 'y'];
function a() {
console.log("a");
}
gulp.task('a', a_deps);
// We are defining task `b`, with dependencies `x` and `q`.
var b_deps = ['x', 'q'];
function b() {
console.log("b");
}
gulp.task('b', b_deps);
// We are defining task `default`, which is equivalent to running tasks
// `a` and `b` in sequence.
gulp.task('default', a_deps.concat(b_deps), function () {
a();
b();
});
郑重声明,我没有使用 run-sequence
,因为当我尝试它时,我看到它 运行 多次绑定我的依赖项,这对我来说是无法接受的。
当 Gulp 4 出来时,我们将能够使用 gulp.series
对任务进行排序
实际上我使用了其他更轻量级的库 run-sequence
,它运行良好且流畅。所以这是示例解决方案:
var sequence = require('run-sequence');
gulp.task('default', function(callback) {
sequence('sass_dev', ['browserify', 'lint'], 'watch', callback);
});
gulp.task('prod', function(callback) {
sequence('sass_dev', ['browserify'], 'uglify', callback);
});