Erreur Gulp: Les tâches suivantes ne se sont pas terminées: Avez-vous oublié de signaler la fin de l'async?

212

J'ai le gulpfile.js suivant , que j'exécute via le message gulp en ligne de commande :

var gulp = require('gulp');

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

Je reçois le message d'erreur suivant:

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

J'utilise gulp 4 sur un système Windows 10. Voici la sortie de gulp --version:

[14:15:15] CLI version 0.4.0
[14:15:15] Local version 4.0.0-alpha.2
John Deighan
la source
1
Si vous êtes ici parce que vous avez un problème webpack-stream. Utilisez ceci: github.com/shama/webpack-stream/issues/…
B3none

Réponses:

447

Étant donné que votre tâche peut contenir du code asynchrone, vous devez signaler gulp lorsque votre tâche a terminé son exécution (= "achèvement asynchrone").

Dans Gulp 3.x, vous pourriez vous en sortir sans faire cela. Si vous n'avez pas explicitement signalé la fin de l'async, Gulp supposerait simplement que votre tâche est synchrone et qu'elle est terminée dès que votre fonction de tâche revient. Gulp 4.x est plus strict à cet égard. Vous devez signaler explicitement la fin de la tâche.

Vous pouvez le faire de six manières :

1. Renvoyer un flux

Ce n'est pas vraiment une option si vous essayez d'imprimer quelque chose, mais c'est probablement le mécanisme d'achèvement asynchrone le plus fréquemment utilisé puisque vous travaillez généralement avec des flux gulp. Voici un exemple (plutôt artificiel) le démontrant pour votre cas d'utilisation:

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

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

La partie importante ici est la returndéclaration. Si vous ne renvoyez pas le flux, gulp ne peut pas déterminer quand le flux est terminé.

2. Retournez un Promise

Il s'agit d'un mécanisme beaucoup plus adapté à votre cas d'utilisation. Notez que la plupart du temps, vous n'aurez pas à créer l' Promiseobjet vous-même, il sera généralement fourni par un package (par exemple, le delpackage fréquemment utilisé renvoie a Promise).

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

L'utilisation de la syntaxe async / attente peut être encore simplifiée. Toutes les fonctions marquées asyncrenvoient implicitement une promesse, de sorte que ce qui suit fonctionne également (si votre version node.js le prend en charge ):

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

3. Appelez la fonction de rappel

C'est probablement le moyen le plus simple pour votre cas d'utilisation: gulp passe automatiquement une fonction de rappel à votre tâche comme premier argument. Appelez simplement cette fonction lorsque vous avez terminé:

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

4. Retourner un processus enfant

Ceci est surtout utile si vous devez appeler un outil de ligne de commande directement car il n'y a pas de wrapper node.js disponible. Cela fonctionne pour votre cas d'utilisation, mais je ne le recommanderais évidemment pas (d'autant plus qu'il n'est pas très portable):

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

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

5. Renvoyez un RxJSObservable .

Je n'ai jamais utilisé ce mécanisme, mais si vous utilisez RxJS, cela pourrait être utile. C'est un peu exagéré si vous voulez juste imprimer quelque chose:

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

Comme le précédent, j'inclus ceci par souci d'exhaustivité, mais ce n'est pas vraiment quelque chose que vous allez utiliser, sauf si vous utilisez déjà un EventEmitterpour une raison quelconque.

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
la source
4
Après quelques heures de recherche sur Google, j'ai trouvé cet exemple. Très utile. Je vous remercie!
paxtor
c'est utile pour moi, ths!
Anan
1
J'apprécie tellement votre réponse. +1 gros temps.
Konrad Viltersten
6
J'ai apprécié votre réponse élégante et informative le 17 novembre. Et aujourd'hui, le jour de Noël, je l'apprécie à nouveau. C'est l'un des cas où j'aimerais pouvoir attribuer +2 ... Je ne peux pas croire que goolearching ne fasse pas sortir ce lien en tête de liste lorsque vous recherchez " Les tâches suivantes ne se sont pas terminées " ou " Avez-vous oublier de signaler la fin de l'async? "...
Konrad Viltersten
msgstr "le paquet del fréquemment utilisé renvoie une promesse". J'utilise del, comment puis-je écrire mon code gulp pour profiter de la promesse? (PS. Réponse absolument incroyable! +1)
Daniel Tonon
84

Un problème avec Gulp 4 .

Pour résoudre ce problème, essayez de modifier votre code actuel:

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

par exemple dans ceci:

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

ou dans ceci:

gulp.task('simpleTaskName', done => {
  // code...
  done();
});
simhumileco
la source
2
L'appel manquant à faire était mon problème. Merci pour votre réponse!
Marco Santarossa
1
Cependant, sachez que les fonctions fléchées n'ont pas de portée distincte.
JepZ
19

Ça a marché!

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
la source
2
c'est la meilleure réponse
Văn Quyết
13

J'obtenais cette même erreur en essayant d'exécuter une construction SASS / CSS très simple .

Ma solution (qui peut résoudre ces mêmes erreurs ou des erreurs similaires) consistait simplement à ajouter donecomme paramètre dans la fonction de tâche par défaut, et à l'appeler à la fin de la tâche par défaut:

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

J'espère que cela t'aides!

KLPA
la source
7
Agréable de voir un exemple avec le contenu réel de la tâche
Jonathan
8

Vous devez faire deux choses:

  1. Ajouter asyncavant la fonction.
  2. Commencez votre fonction avec return.

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

Je ne peux pas prétendre être très bien informé à ce sujet mais j'ai eu le même problème et je l'ai résolu.

Il existe une 7e façon de résoudre ce problème en utilisant une fonction asynchrone .

Écrivez votre fonction mais ajoutez le préfixe async .

En faisant cela, Gulp encapsule la fonction dans une promesse et la tâche s'exécutera sans erreur.

Exemple:

async function() {
  // do something
};

Ressources:

  1. Dernière section de la page Gulp Achèvement asynchrone : utilisation asynchrone / wait .

  2. Documents sur les fonctions asynchrones de Mozilla .

Jonny
la source
7

C'est un problème lors de la migration de gulp version 3 vers 4, vous pouvez simplement ajouter un paramètre fait à la fonction de rappel, voir exemple,

   const gulp = require("gulp")

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

Solution: nous devons appeler les fonctions de rappel (tâche et anonyme):

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

Et voilà: pas de tâches synchrones .

Pas de tâches synchrones

Les tâches synchrones ne sont plus prises en charge. Ils ont souvent conduit à des erreurs subtiles difficiles à déboguer, comme oublier de renvoyer vos flux d'une tâche.

Lorsque vous voyez l' Did you forget to signal async completion?avertissement, aucune des techniques mentionnées ci-dessus n'a été utilisée. Vous devrez utiliser le rappel d'erreur en premier ou renvoyer un flux, une promesse, un émetteur d'événement, un processus enfant ou observable pour résoudre le problème.

Utilisation de async/await

Lorsque vous n'utilisez aucune des options précédentes, vous pouvez définir votre tâche en tant que async function, ce qui l'enveloppe dans une promesse . Cela vous permet de travailler avec des promesses de manière synchrone awaitet d'utiliser un autre code synchrone.

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
la source
2

Fondamentalement, v3.X était plus simple, mais v4.x est strict dans ces moyens de tâches synchrones et asynchrones.

L' async / attente est un moyen assez simple et utile de comprendre le flux de travail et le problème.

Utilisez cette approche simple

const gulp = require('gulp')

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

Je me débattais avec cela récemment et j'ai trouvé la bonne façon de créer une defaulttâche qui s'exécutait sassalors sass:watch:

gulp.task('default', gulp.series('sass', 'sass:watch'));
Navire Howard M. Lewis
la source
1

Ma solution: mettez tout avec async et attendez gulp.

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
la source
1

Vous devez faire une chose:

  • Ajouter asyncavant la fonction.

const gulp = require('gulp');

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

Chinthani Sugandhika
la source
0

Ajoutez done comme paramètre dans la fonction par défaut. Cela fera l'affaire.

bmayur
la source
0

Pour ceux qui essaient d'utiliser gulp pour le déploiement local de swagger, le code suivant vous aidera

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
la source
0

Pour moi, le problème était différent: Angular-cli n'était pas installé (j'ai installé une nouvelle version de Node à l'aide de NVM et j'ai simplement oublié de réinstaller angular cli)

Vous pouvez vérifier l'exécution de "ng version".

Si vous ne l'avez pas, lancez simplement "npm install -g @ angular / cli"

Ari Waisberg
la source