Error de trago: Las siguientes tareas no se completaron: ¿Se olvidó de indicar la finalización asincrónica?

212

Tengo el siguiente gulpfile.js , que estoy ejecutando a través del mensaje de salto de línea de comando :

var gulp = require('gulp');

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

Recibo el siguiente mensaje de error:

[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?

Estoy usando gulp 4 en un sistema Windows 10. Aquí está la salida de gulp --version:

[14:15:15] CLI version 0.4.0
[14:15:15] Local version 4.0.0-alpha.2
John Deighan
fuente
1
Si estás aquí porque tienes un problema con webpack-stream. Use esto: github.com/shama/webpack-stream/issues/…
B3none el

Respuestas:

447

Dado que su tarea puede contener código asincrónico, debe indicar un trago cuando su tarea haya terminado de ejecutarse (= "finalización asíncrona").

En Gulp 3.x puedes escapar sin hacer esto. Si no indicó explícitamente la finalización asincrónica, solo supondría que su tarea es sincrónica y que finaliza tan pronto como regrese la función de la tarea. Gulp 4.x es más estricto a este respecto. Tienes que indicar explícitamente la realización de tareas.

Puedes hacerlo de seis maneras :

1. Devolver una transmisión

Esta no es realmente una opción si solo está tratando de imprimir algo, pero es probablemente el mecanismo de finalización asíncrona más utilizado ya que generalmente está trabajando con flujos de tragos. Aquí hay un ejemplo (bastante artificial) que lo demuestra para su caso de uso:

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

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

La parte importante aquí es la returndeclaración. Si no devuelve la transmisión, trago no puede determinar cuándo la transmisión ha finalizado.

2. Devolver a Promise

Este es un mecanismo mucho más apropiado para su caso de uso. Tenga en cuenta que la mayoría de las veces no tendrá que crear el Promiseobjeto usted mismo, generalmente lo proporcionará un paquete (por ejemplo, el delpaquete utilizado con frecuencia devuelve a Promise).

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

El uso de la sintaxis async / await puede simplificarse aún más. Todas las funciones marcadas asyncdevuelven implícitamente una Promesa, por lo que lo siguiente también funciona (si su versión node.js lo admite ):

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

3. Llame a la función de devolución de llamada

Esta es probablemente la forma más fácil para su caso de uso: gulp pasa automáticamente una función de devolución de llamada a su tarea como primer argumento. Simplemente llame a esa función cuando haya terminado:

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

4. Devolver un proceso hijo

Esto es principalmente útil si tiene que invocar una herramienta de línea de comandos directamente porque no hay un contenedor node.js disponible. Funciona para su caso de uso, pero obviamente no lo recomendaría (especialmente porque no es muy portátil):

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

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

5. Devuelva un RxJSObservable .

Nunca he usado este mecanismo, pero si estás usando RxJS podría ser útil. Es una exageración si solo quieres imprimir algo:

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. Devuelve un EventEmitter

Al igual que el anterior, lo incluyo por razones de integridad, pero en realidad no es algo que vaya a usar a menos que ya lo esté usando EventEmitterpor alguna razón.

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;
});
Sven Schoenung
fuente
44
Después de un par de horas buscando en Google, encontré este ejemplo. Muy útil. ¡Gracias!
paxtor
¡Es útil para mí!
Anan
1
Agradezco mucho tu respuesta. +1 a lo grande.
Konrad Viltersten
66
Aprecié su respuesta elegante e informativa el 17 de noviembre. Y hoy, el día de Navidad, lo estoy apreciando nuevamente. Este es uno de los casos en los que desearía poder otorgar +2 ... No puedo creer que goolearching no ubique este enlace como el número 1 al buscar " Las siguientes tareas no se completaron " o " ¿Usted ¿
Olvidaste
"el paquete del del uso frecuente devuelve una promesa". Estoy usando del, ¿cómo escribo mi código para aprovechar la promesa? (PD. ¡Respuesta absolutamente increíble! +1)
Daniel Tonon
84

Un problema con Gulp 4 .

Para resolver este problema, intente cambiar su código actual:

gulp.task('simpleTaskName', function() {
  // code...
});

por ejemplo en esto:

gulp.task('simpleTaskName', async function() {
  // code...
});

o en esto:

gulp.task('simpleTaskName', done => {
  // code...
  done();
});
simhumileco
fuente
2
La llamada que faltaba era mi problema. ¡Gracias por su respuesta!
Marco Santarossa
1
Sin embargo, tenga en cuenta que las funciones de flecha no tienen un alcance separado.
JepZ
19

Esto funcionó!

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

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

gulp.task('default', gulp.parallel(
        'script',
        'css'
  )
);
Khachornchit Songsaen
fuente
2
esta es la mejor respuesta
Văn Quyết
13

Recibía el mismo error al intentar ejecutar una compilación SASS / CSS muy simple .

Mi solución (que puede resolver este mismo error o uno similar) fue simplemente agregar donecomo parámetro en la función de tarea predeterminada y llamarlo al final de la tarea predeterminada:

// 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.
})

¡Espero que esto ayude!

KLPA
fuente
77
Es bueno ver un ejemplo con el contenido real de la tarea
Jonathan
8

Necesitas hacer dos cosas:

  1. Añadir asyncantes de la función.
  2. Comience su función con return.

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

No puedo decir que tengo mucho conocimiento sobre esto, pero tuve el mismo problema y lo resolví.

Hay una séptima forma de resolver esto, utilizando una función asíncrona .

Escriba su función pero agregue el prefijo asíncrono .

Al hacer esto, Gulp envuelve la función en una promesa, y la tarea se ejecutará sin errores.

Ejemplo:

async function() {
  // do something
};

Recursos:

  1. Última sección en la página Gulp Finalización asincrónica : Uso de async / await .

  2. Funciones asíncronas de Mozilla docs .

Jonny
fuente
7

Este es un problema al migrar de la versión 3 a 4 de Gulp. Simplemente puede agregar un parámetro hecho a la función de devolución de llamada, consulte el ejemplo,

   const gulp = require("gulp")

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

Solución alternativa: Necesitamos llamar a las funciones de devolución de llamada (Tarea y Anónimo):

function electronTask(callbackA)
{
    return gulp.series(myFirstTask, mySeccondTask, (callbackB) =>
    {
        callbackA();
        callbackB();
    })();    
}
Jackes David Lemos
fuente
2

Aquí tienes: no hay tareas sincrónicas .

Sin tareas sincrónicas

Las tareas sincrónicas ya no son compatibles. A menudo conducían a errores sutiles que eran difíciles de depurar, como olvidarse de devolver las transmisiones de una tarea.

Cuando veas el Did you forget to signal async completion? advertencia, ninguna de las técnicas mencionadas anteriormente se utilizó. Deberá usar la devolución de llamada de primer error o devolver una transmisión, promesa, emisor de eventos, proceso secundario u observable para resolver el problema.

Usando async/await

Cuando no use ninguna de las opciones anteriores, puede definir su tarea como una async function, que envuelve su tarea en una promesa . Esto le permite trabajar con promesas sincrónicamente usando awaity usando otro código sincrónico.

const fs = require('fs');

async function asyncAwaitTask() {
  const { version } = fs.readFileSync('package.json');
  console.log(version);
  await Promise.resolve('some result');
}

exports.default = asyncAwaitTask;
Lloyd Apter
fuente
2

Básicamente, v3.X era más simple, pero v4.x es estricto en estos medios de tareas síncronas y asíncronas.

El asíncrono / espera es bastante simple y forma útil para entender el flujo de trabajo y edición.

Use este enfoque simple

const gulp = require('gulp')

gulp.task('message',async function(){
return console.log('Gulp is running...')
})
Naveen Nirban Yadav
fuente
1

Estaba luchando con esto recientemente, y encontré que la forma correcta de crear una defaulttarea que se ejecutara sassentonces sass:watchera:

gulp.task('default', gulp.series('sass', 'sass:watch'));
Howard M. Lewis Barco
fuente
1

Mi solución: poner todo con asíncrono y esperar tragar.

async function min_css() {
    return await gulp
        .src(cssFiles, { base: "." })
        .pipe(concat(cssOutput))
        .pipe(cssmin())
        .pipe(gulp.dest("."));
}

async function min_js() {
    return await gulp
        .src(jsFiles, { base: "." })
        .pipe(concat(jsOutput))
        .pipe(uglify())
        .pipe(gulp.dest("."));  
}

const min = async () => await gulp.series(min_css, min_js);

exports.min = min;
Kat Lim Ruiz
fuente
1

Necesitas hacer una cosa:

  • Añadir asyncantes de la función.

const gulp = require('gulp');

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

Chinthani Sugandhika
fuente
0

Agregar hecho como parámetro en la función predeterminada. Que hará.

bmayur
fuente
0

Para aquellos que están tratando de usar Gulp para la implementación local swagger, el siguiente código ayudará

var gulp = require("gulp");
var yaml = require("js-yaml");
var path = require("path");
var fs = require("fs");

//Converts yaml to json
gulp.task("swagger", done => {
    var doc = yaml.safeLoad(fs.readFileSync(path.join(__dirname,"api/swagger/swagger.yaml")));
    fs.writeFileSync(
        path.join(__dirname,"../yourjsonfile.json"),
        JSON.stringify(doc, null, " ")
        );
    done();
});

//Watches for changes    
gulp.task('watch', function() {
  gulp.watch('api/swagger/swagger.yaml', gulp.series('swagger'));  
});
hellowahab
fuente
0

Para mí, el problema era diferente: Angular-cli no estaba instalado (instalé una nueva versión de Node usando NVM y simplemente olvidé reinstalar angular cli)

Puede verificar la ejecución de "ng version".

Si no lo tiene, simplemente ejecute "npm install -g @ angular / cli"

Ari Waisberg
fuente