Erro de gole: As seguintes tarefas não foram concluídas: Você esqueceu de sinalizar a conclusão do assíncrono?

212

Eu tenho o seguinte gulpfile.js , que estou executando através da mensagem gulp da linha de comando :

var gulp = require('gulp');

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

Estou recebendo a seguinte mensagem de erro:

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

Estou usando o gulp 4 em um sistema Windows 10. Aqui está a saída de gulp --version:

[14:15:15] CLI version 0.4.0
[14:15:15] Local version 4.0.0-alpha.2
John Deighan
fonte
1
Se você está aqui porque tem um problema webpack-stream. Use isto: github.com/shama/webpack-stream/issues/…
B3none 01/04/19

Respostas:

448

Como sua tarefa pode conter código assíncrono, é necessário sinalizar gulp quando a tarefa terminar de executar (= "conclusão assíncrona").

No Gulp 3.x, você pode fugir sem fazer isso. Se você não sinalizou explicitamente o gulp de conclusão assíncrona, apenas assumiria que sua tarefa é síncrona e que é concluída assim que sua função de tarefa retornar. Gulp 4.x é mais rigoroso nesse sentido. Você precisa sinalizar explicitamente a conclusão da tarefa.

Você pode fazer isso de seis maneiras :

1. Retornar um fluxo

Essa não é realmente uma opção se você está apenas tentando imprimir algo, mas é provavelmente o mecanismo de conclusão assíncrona mais frequentemente usado, já que você geralmente trabalha com fluxos gulp. Aqui está um exemplo (bastante artificial) que demonstra isso para o seu caso de uso:

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

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

A parte importante aqui é a returndeclaração. Se você não retornar o fluxo, o gulp não poderá determinar quando o fluxo terminou.

2. Retorne um Promise

Esse é um mecanismo muito mais adequado para o seu caso de uso. Observe que na maioria das vezes você não precisará criar o Promiseobjeto, ele geralmente será fornecido por um pacote (por exemplo, o delpacote usado com freqüência retorna a Promise).

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

Usando a sintaxe assíncrona / aguardada, isso pode ser simplificado ainda mais. Todas as funções marcadas asyncimplicitamente retornam uma promessa, para que o seguinte também funcione (se a versão do node.js. suportar ):

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

3. Chame a função de retorno de chamada

Esta é provavelmente a maneira mais fácil para o seu caso de uso: o gulp passa automaticamente uma função de retorno de chamada para sua tarefa como seu primeiro argumento. Basta chamar essa função quando terminar:

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

4. Retornar um processo filho

Isso é útil principalmente se você precisar chamar uma ferramenta de linha de comando diretamente, porque não há nenhum wrapper node.j disponível. Funciona para o seu caso de uso, mas obviamente eu não o recomendaria (especialmente porque não é muito portátil):

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

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

5. Retorne um RxJSObservable .

Eu nunca usei esse mecanismo, mas se você estiver usando o RxJS, pode ser útil. É meio exagero se você quiser 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. Retorne um EventEmitter

Como o anterior, estou incluindo isso por uma questão de integridade, mas não é algo que você usará, a menos que já esteja usando um EventEmitterpor algum motivo.

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
fonte
4
Após algumas horas pesquisando no google, encontrei este exemplo. Muito útil. Obrigado!
paxtor
é útil para mim, ths!
Anan
1
Eu aprecio muito sua resposta. +1 um grande momento.
Konrad Viltersten
6
Apreciei sua resposta elegante e informativa em 17 de novembro. E hoje, no dia de Natal, estou apreciando tudo de novo. Este é um dos casos em que eu gostaria de atribuir +2 ... Não acredito que o goolearching não aponte esse link como o principal # 1 ao procurar " As tarefas a seguir não foram concluídas " ou " Você esquece de sinalizar conclusão assíncrona? "...
Konrad Viltersten
"o pacote del usado com freqüência retorna uma promessa". Estou usando del, como escrevo meu código gulp para aproveitar a promessa? (. PS resposta Absolutamente incrível +1!)
Daniel Tonon
84

Um problema com o Gulp 4 .

Para resolver esse problema, tente alterar seu código atual:

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

por exemplo, para isso:

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

ou para isso:

gulp.task('simpleTaskName', done => {
  // code...
  done();
});
simhumileco
fonte
2
A ligação que faltava foi o meu problema. Obrigado pela sua resposta!
Marco Santarossa
1
No entanto, esteja ciente de que as funções de seta não têm escopo separado.
JepZ 9/08/19
19

Isso funcionou!

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
fonte
2
este é melhor resposta
Văn Quyết
13

Eu estava recebendo o mesmo erro ao tentar executar uma compilação SASS / CSS muito simples .

Minha solução (que pode resolver esses erros iguais ou semelhantes) foi simplesmente adicionar donecomo parâmetro na função de tarefa padrão e chamá-lo no final da tarefa padrão:

// 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 isto ajude!

KLPA
fonte
7
Bom ver um exemplo com conteúdos tarefa real
Jonathan
8

Você precisa fazer duas coisas:

  1. Adicionar asyncantes da função.
  2. Comece sua função com return.

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

Não posso afirmar que tenho muito conhecimento disso, mas tive o mesmo problema e o resolvi.

Existe uma sétima maneira de resolver isso, usando uma função assíncrona .

Escreva sua função, mas adicione o prefixo assíncrono .

Ao fazer isso, o Gulp envolve a função em uma promessa e a tarefa será executada sem erros.

Exemplo:

async function() {
  // do something
};

Recursos:

  1. Última seção da página Gulp Conclusão assíncrona : Usando async / waitit .

  2. Mozilla funções assíncronas docs .

Jonny
fonte
7

Esse é um problema ao migrar da versão 3 para 4 do gulp. Simplesmente, você pode adicionar um parâmetro feito à função de retorno de chamada, veja o exemplo,

   const gulp = require("gulp")

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

Solução alternativa: precisamos chamar as funções de retorno de chamada (Tarefa e Anônimo):

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

Aqui você vai: Nenhuma tarefa síncrona .

Nenhuma tarefa síncrona

Tarefas síncronas não são mais suportadas. Eles geralmente levavam a erros sutis que eram difíceis de depurar, como esquecer de retornar seus fluxos de uma tarefa.

Quando você vê o Did you forget to signal async completion? aviso, nenhuma das técnicas mencionadas acima foi usada. Você precisará usar a primeira chamada de erro ou retornar um fluxo, promessa, emissor de evento, processo filho ou observável para resolver o problema.

Usando async/await

Quando não estiver usando nenhuma das opções anteriores, você pode definir sua tarefa como uma async function, que envolve sua tarefa em uma promessa . Isso permite que você trabalhe com promessas de forma síncrona usando awaite usando outro código síncrono.

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
fonte
2

Basicamente, o v3.X era mais simples, mas o v4.x é rigoroso nesses meios de tarefas síncronas e assíncronas.

O assíncrono / espera é uma maneira bastante simples e útil de entender o fluxo de trabalho e o problema.

Use esta abordagem simples

const gulp = require('gulp')

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

Eu estava lutando com isso recentemente e encontrei o caminho certo para criar uma defaulttarefa que é executada na sassépoca sass:watch:

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

Minha solução: coloque tudo com assíncrono e aguarde gole.

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
fonte
1

Você precisa fazer uma coisa:

  • Adicionar asyncantes da função.

const gulp = require('gulp');

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

Chinthani Sugandhika
fonte
0

Adicione done como parâmetro na função padrão. Que vai fazer.

bmayur
fonte
0

Para aqueles que estão tentando usar gulp para implantação local arrogante, o código a seguir ajudará

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
fonte
0

Para mim, o problema era diferente: o Angular-cli não estava instalado (instalei uma nova versão do Node usando o NVM e simplesmente esqueci de reinstalar o angular cli)

Você pode verificar a "versão ng" em execução.

Se você não o tiver, execute "npm install -g @ angular / cli"

Ari Waisberg
fonte