且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2022-03-03 22:24:40

由于您的任务可能包含异步代码,因此您必须在任务完成执行时发出 gulp 信号(=异步完成").

Since your task might contain asynchronous code you have to signal gulp when your task has finished executing (= "async completion").

在 Gulp 3.x 中,您无需这样做就可以逃脱.如果你没有明确表示异步完成,gulp 只会假设你的任务是同步的,并且一旦你的任务函数返回它就完成了.Gulp 4.x 在这方面更加严格.您必须明确表示任务完成.

In Gulp 3.x you could get away without doing this. If you didn't explicitly signal async completion gulp would just assume that your task is synchronous and that it is finished as soon as your task function returns. Gulp 4.x is stricter in this regard. You have to explicitly signal task completion.

您可以通过六种方式做到这一点:

You can do that in six ways:

如果您只是想打印一些东西,这并不是一个真正的选择,但它可能是最常用的异步完成机制,因为您通常使用 gulp 流.这是一个(相当人为的)示例,为您的用例演示它:

This is not really an option if you're only trying to print something, but it's probably the most frequently used async completion mechanism since you're usually working with gulp streams. Here's a (rather contrived) example demonstrating it for your use case:

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

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

这里的重要部分是 return 语句.如果您不返回流,gulp 无法确定流何时结束.

The important part here is the return statement. If you don't return the stream, gulp can't determine when the stream has finished.

这是一个更适合您的用例的机制.请注意,大多数时候您不必自己创建 Promise 对象,它通常由一个包提供(例如,经常使用的 del 包返回 Promise).

This is a much more fitting mechanism for your use case. Note that most of the time you won't have to create the Promise object yourself, it will usually be provided by a package (e.g. the frequently used del package returns a Promise).

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

使用 async/await 语法可以进一步简化.所有标记为 async 的函数都隐式返回 Promise,因此以下内容也可以使用(如果您的 node.js 版本支持):

Using async/await syntax this can be simplified even further. All functions marked async implicitly return a Promise so the following works too (if your node.js version supports it):

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

3.调用回调函数

对于您的用例,这可能是最简单的方法:gulp 会自动将回调函数作为第一个参数传递给您的任务.完成后调用该函数:

3. Call the callback function

This is probably the easiest way for your use case: gulp automatically passes a callback function to your task as its first argument. Just call that function when you're done:

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

4.返回一个子进程

如果您必须直接调用命令行工具,这非常有用,因为没有可用的 node.js 包装器.它适用于您的用例,但显然我不推荐它(特别是因为它不是很便携):

4. Return a child process

This is mostly useful if you have to invoke a command line tool directly because there's no node.js wrapper available. It works for your use case but obviously I wouldn't recommend it (especially since it's not very portable):

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

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

5.返回一个 RxJS Observable.

我从未使用过这种机制,但如果您使用的是 RxJS,它可能会很有用.如果你只是想打印一些东西,那就有点矫枉过正了:

5. Return a RxJS Observable.

I've never used this mechanism, but if you're using RxJS it might be useful. It's kind of overkill if you just want to print something:

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,否则您实际上不会使用它.

6. Return an EventEmitter

Like the previous one I'm including this for completeness sake, but it's not really something you're going to use unless you're already using an EventEmitter for some reason.

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;
});