Gulp错误:以下任务未完成:您是否忘记信号异步完成?

334

我有以下的 gulpfile.js,我通过命令行 gulp message 来执行它:

var gulp = require('gulp');

gulp.task('message', function() {
  console.log("HTTP Server Started");
});
我收到了以下错误信息:

[14:14:41] Using gulpfile ~\Documents\node\first\gulpfile.js
[14:14:41] Starting 'message'...
HTTP Server Started
[14:14:41] The following tasks did not complete: message
[14:14:41] Did you forget to signal async completion?

我正在 Windows 10 系统上使用 gulp 4。以下是 gulp --version 的输出结果:

[14:15:15] CLI version 0.4.0
[14:15:15] Local version 4.0.0-alpha.2

1
如果您在这里是因为使用webpack-stream出现了问题,请使用以下链接:https://github.com/shama/webpack-stream/issues/34#issuecomment-478602446 - B3none
22个回答

623

由于您的任务可能包含异步代码,因此必须在任务执行完成时向gulp发出信号,表示“异步完成”。

在Gulp 3.x中,您可以不这样做。如果您没有明确地发出异步完成信号,gulp将假定您的任务是同步的,并且一旦您的任务函数返回,它就已经完成了。Gulp 4.x在这方面更加严格。您必须明确发出任务完成信号。

六种方法可以做到这一点:

1. 返回

如果你只是想打印一些东西,这并不是一个真正的选项,但这可能是最常用的异步完成机制,因为你通常使用gulp流。以下是一个(相当牵强附会的)示例,演示了如何为您的用例使用它:

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

gulp.task('message', function() {
  return gulp.src('package.json')
    .pipe(print(function() { return 'HTTP Server Started'; }));
});

重要的部分在于 return 语句。如果没有返回流,gulp 则无法确定流何时结束。

2. 返回一个Promise

对于您的使用场景来说,这是一个更加合适的机制。请注意,大多数情况下您不需要自己创建 Promise 对象,它通常会由一个包(例如经常使用的del 包返回一个 Promise)提供。

gulp.task('message', function() { 
  return new Promise(function(resolve, reject) {
    console.log("HTTP Server Started");
    resolve();
  });
});

使用 async/await 语法可以进一步简化代码。所有标记为 async 的函数都会隐式返回一个Promise,所以下面的代码也可以工作(如果你的node.js版本支持它):

gulp.task('message', async function() {
  console.log("HTTP Server Started");
});

3. 调用回调函数

这可能是您的使用情况中最简单的方法:Gulp会自动将回调函数作为其第一个参数传递给您的任务。完成时只需调用该函数即可:

gulp.task('message', function(done) {
  console.log("HTTP Server Started");
  done();
});

4. 返回一个子进程

如果您需要直接调用命令行工具,因为没有可用的node.js包装器,则此选项非常有用。它可以解决您的使用情况,但显然我不建议使用(特别是因为它不太可移植):

var spawn = require('child_process').spawn;

gulp.task('message', function() {
  return spawn('echo', ['HTTP', 'Server', 'Started'], { stdio: 'inherit' });
});

5. 返回一个RxJS Observable

我从未使用过这种机制,但如果您正在使用 RxJS,它可能很有用。如果您只是想打印一些东西,那么这可能有点过度设计:

var of = require('rxjs').of;

gulp.task('message', function() {
  var o = of('HTTP Server Started');
  o.subscribe(function(msg) { console.log(msg); });
  return o;
});

6. 返回一个EventEmitter

像之前一样,我将其包含在内是为了完整性,但除非您已经出于某种原因在使用 EventEmitter,否则您不会真正使用它。

gulp.task('message3', function() {
  var e = new EventEmitter();
  e.on('msg', function(msg) { console.log(msg); });
  setTimeout(() => { e.emit('msg', 'HTTP Server Started'); e.emit('finish'); });
  return e;
});

14
我很欣赏你在11月17日给出的优雅而富有启发性的回答。今天,在圣诞节,我再次感到很感激。这是一个我希望能够奖励+2的情况之一...我简直不敢相信,当搜索“The following tasks did not complete”或“*Did you forget to signal async completion?*”时,谷歌竟然没有将此链接排名第一... - Konrad Viltersten
我看过一些 Gulp 4 的示例,比如这个,其中观察者似乎没有附带完成信号。这里是什么在发出异步完成信号?gulp.watch() 有什么独特之处,还是他应该使用你列出的方法之一? - Corey
添加另一个关于Gulp 4的相关链接,供那些需要的人使用:https://dev59.com/eI7ea4cB1Zd3GeqPHu1Q#32704073 - SJL
第三步:调用回调函数。当你需要等待管道完成时,正确的写法是 .pipe(...).on('finish', done)(或者根据你的管道是 'end')。 - fabb
1
谢谢!那个单一的返回值解决了我的问题,我在重用旧的gulp3代码并更新到gulp4时已经寻找了相当长的时间。 - Heimson
显示剩余7条评论

145

Gulp 4的问题.

为了解决此问题,请尝试更改您当前的代码:

gulp.task('simpleTaskName', function() {
  // code...
});
例如,转化为这个:
gulp.task('simpleTaskName', async function() {
  // code...
});

或者变成这样:

gulp.task('simpleTaskName', done => {
  // code...
  done();
});

2
缺少对done的调用是我的问题。谢谢你的回答! - Marco Santarossa
1
但要注意的是箭头函数没有独立的作用域。 - JepZ
5
异步函数(async function)是最简单、最快速的解决方案。+1 - Hasan Alsawadi

35

你需要做一件事情:

  • 在函数前添加async
const gulp = require('gulp');

gulp.task('message', async function() {
    console.log("Gulp is running...");
});

28

这个有效了!

2021年2月18日的最新更新:在使用下面旧的解决方案后,我发现了问题,然后使用以下方法来修复了下一个gulp版本中的问题。

文件:Package.json

...,
"devDependencies": {
        "del": "^6.0.0",
        "gulp": "^4.0.2",
      },
...

文件: gulpfile.js 示例

const {task} = require('gulp');
const del = require('del');

async function clean() {
    console.log('processing ... clean');

    return del([__dirname + '/dist']);
}

task(clean)
...

老年版

gulp.task('script', done => {
    // ... code gulp.src( ... )
    done();
});

gulp.task('css', done => {
    // ... code gulp.src( ... )
    done();
});

gulp.task('default', gulp.parallel(
        'script',
        'css'
  )
);

2
将旧项目升级到Gulp 4.x后,这就解决了我的问题。谢谢! - burgoyne
1
@Anton,我在发现一个新问题后已经更新了上述内容,并且最近于2021年2月18日进行了修复。 - KHACHORNCHIT
2
太好了,这个答案节省了我很多时间!!!谢谢@KhachornchitSongsaen,这应该是被接受的答案! - Nawaz

13

我在尝试运行一个非常简单的 SASS/CSS 构建时遇到了相同的错误。

我的解决方案(可能会解决这个或类似的错误)只是在默认任务函数中添加done作为参数,并在默认任务的末尾调用它:

// Sass configuration
var gulp = require('gulp');
var sass = require('gulp-sass');

gulp.task('sass', function () {
    gulp.src('*.scss')
        .pipe(sass())
        .pipe(gulp.dest(function (f) {
            return f.base;
        }))
});

gulp.task('clean', function() {
})

gulp.task('watch', function() {
    gulp.watch('*.scss', ['sass']);
})


gulp.task('default', function(done) { // <--- Insert `done` as a parameter here...
    gulp.series('clean','sass', 'watch')
    done(); // <--- ...and call it here.
})
希望这有所帮助!

7
很高兴看到有实际任务内容的例子。 - Jonathan
2
如果您在gulp.series()之后立即调用done(),则似乎不会等待任务系列完成。也许进程在退出之前会等待,但是如果您尝试将其组合成更大的任务结构,则似乎无法正常工作。 - 1j01

12

当从 gulp 3 迁移至 4 版本时,会出现一个问题。简单地,您可以在回调函数中添加参数 done。请参考以下示例:

   const gulp = require("gulp")

    gulp.task("message", function(done) {
      console.log("Gulp is running...")
      done()
    });

8

您需要完成两件事:

  1. Add async before function.
  2. Start your function with return.

    var gulp = require('gulp');
    
    gulp.task('message', async function() {
        return console.log("HTTP Server Started");
    });
    

8

虽然我对此不是很了解,但我遇到了同样的问题并已经解决了。

有第七种解决方法,即使用async函数

编写您的函数,但添加前缀async

这样做可以让Gulp将该函数包装在一个Promise中,并且任务将无错误运行。

示例:

async function() {
  // do something
};

资源:

  1. Gulp页面上的最后一部分 Async Completion: 使用 async/await.

  2. Mozilla async 函数文档.


7

解决方法:我们需要调用回调函数(任务和匿名函数):

function electronTask(callbackA)
{
    return gulp.series(myFirstTask, mySeccondTask, (callbackB) =>
    {
        callbackA();
        callbackB();
    })();    
}

5

基本上,v3.X版本更简单,而v4.X版本在同步和异步任务方面更加严格。

async/await是一种非常简单和有帮助的方式,可用于理解工作流程和问题。

使用这种简单的方法。

const gulp = require('gulp')

gulp.task('message',async function(){
return console.log('Gulp is running...')
})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接