【问题标题】:Async.js with Gulp turns error "Callback was already called"带有 Gulp 的 Async.js 会出现错误“回调已被调用”
【发布时间】:2015-10-28 22:15:28
【问题描述】:

我正在使用 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 条件下它也不起作用。有人可以帮忙吗?

【问题讨论】:

    标签: javascript asynchronous reactjs package gulp


    【解决方案1】:

    问题

    您遇到此问题的原因是您正在使用 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.

    安全的解决方案

    无论如何。看来您想按顺序运行一堆任务。我过去这样做的方式是声明将按顺序运行其他任务的任务,以便:

    1. 它的依赖是依次运行的任务的所有依赖的并集。

    2. 它的实现函数调用它应该依次运行的所有任务的实现函数。

    这是一个简单的例子:

    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 npmjs.com/package/run-sequence
    • 是的,我在回答中确实提到了run-sequence
    【解决方案2】:

    有一个更简单的方法。

    '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']);

    【讨论】:

      【解决方案3】:

      实际上,我使用了其他更轻的库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);
      });
      

      npm link

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-10-02
        • 2017-06-23
        • 2020-06-14
        • 2017-03-04
        • 1970-01-01
        • 1970-01-01
        • 2016-11-22
        相关资源
        最近更新 更多