Błąd łyka: Następujące zadania nie zostały zakończone: Czy zapomniałeś zasygnalizować zakończenie asynchronizacji?

211

Mam następujący plik gulpfile.js , który wykonuję za pomocą komunikatu gulp z wiersza poleceń :

var gulp = require('gulp');

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

Otrzymuję następujący komunikat o błędzie:

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

Używam gulp 4 w systemie Windows 10. Oto dane wyjściowe z gulp --version:

[14:15:15] CLI version 0.4.0
[14:15:15] Local version 4.0.0-alpha.2
John Deighan
źródło
1
Jeśli jesteś tutaj, ponieważ masz problem z webpack-stream. Użyj tego: github.com/shama/webpack-stream/issues/…
B3none

Odpowiedzi:

448

Ponieważ Twoje zadanie może zawierać kod asynchroniczny, musisz zasygnalizować łyk, gdy zadanie zakończy się (= „zakończenie asynchroniczne”).

W Gulp 3.x można było uciec bez robienia tego. Jeśli nie zasygnalizowałeś jawnie zakończenia asynchronicznego, gulp po prostu przyjmie, że twoje zadanie jest synchroniczne i że jest ukończone, gdy tylko funkcja zadania powróci. Gulp 4.x jest pod tym względem surowszy. Państwo musi wyraźnie sygnalizować zakończenie zadania.

Możesz to zrobić na sześć sposobów :

1. Zwróć strumień

Nie jest to tak naprawdę opcja, jeśli próbujesz tylko coś wydrukować, ale prawdopodobnie jest to najczęściej używany mechanizm uzupełniania asynchronicznego, ponieważ zwykle pracujesz ze strumieniami gulp. Oto (raczej wymyślony) przykład demonstrujący to dla twojego przypadku użycia:

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

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

Ważną częścią tutaj jest returnstwierdzenie. Jeśli nie zwrócisz strumienia, gulp nie może określić, kiedy strumień się zakończył.

2. Zwróć a Promise

Jest to o wiele bardziej odpowiedni mechanizm dla twojego przypadku użycia. Zauważ, że przez większość czasu nie musisz samodzielnie tworzyć Promiseobiektu, zwykle jest on dostarczany przez pakiet (np. Często używany delpakiet zwraca a Promise).

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

Za pomocą składni async / await można to jeszcze bardziej uprościć. Wszystkie funkcje oznaczone w asyncsposób dorozumiany zwracają obietnicę, więc działają również następujące funkcje (jeśli obsługuje ją wersja node.js ):

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

3. Wywołaj funkcję oddzwaniania

Jest to prawdopodobnie najłatwiejszy sposób użycia w przypadku użycia: gulp automatycznie przekazuje funkcję zwrotną do zadania jako pierwszy argument. Po zakończeniu wywołaj tę funkcję:

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

4. Zwróć a proces potomny

Jest to szczególnie przydatne, jeśli musisz bezpośrednio wywołać narzędzie wiersza poleceń, ponieważ nie ma dostępnego opakowania node.js. Działa w twoim przypadku użycia, ale oczywiście nie poleciłbym go (zwłaszcza, że ​​nie jest zbyt przenośny):

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

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

5. Zwróć RxJSObservable .

Nigdy nie korzystałem z tego mechanizmu, ale jeśli używasz RxJS, może się przydać. To rodzaj przesady, jeśli po prostu chcesz coś wydrukować:

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. Zwróć an EventEmitter

Podobnie jak poprzedni, włączam to ze względu na kompletność, ale tak naprawdę nie będzie to coś, czego będziesz używać, chyba że EventEmitterz jakiegoś powodu już go używasz .

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
źródło
4
Po kilku godzinach googlowania znalazłem ten przykład. Bardzo pomocne. Dziękuję Ci!
paxtor
jest to dla mnie pomocne, ths!
Anan
1
Doceniam twoją odpowiedź. +1 duży czas.
Konrad Viltersten
6
Doceniam twoją elegancką i pouczającą odpowiedź 17 listopada. A dzisiaj, w Boże Narodzenie, doceniam to wszystko od nowa. Jest to jeden z przypadków, w których chciałbym przyznać +2 ... Nie mogę uwierzyć, że goolearching nie usuwa tego linku jako pierwszej pozycji w rankingu „ Następujące zadania nie zostały ukończone ” lub „ Czy zapomnieć zasygnalizować zakończenie asynchroniczne? ”...
Konrad Viltersten
„często używany pakiet del zwraca obietnicę”. Korzystam z del. Jak mam napisać kod GULP, aby skorzystać z obietnicy? (PS. Absolutnie niesamowita odpowiedź! +1)
Daniel Tonon
84

Problem z Gulp 4 .

Aby rozwiązać ten problem, spróbuj zmienić swój obecny kod:

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

na przykład do tego:

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

lub w to:

gulp.task('simpleTaskName', done => {
  // code...
  done();
});
simhumileco
źródło
2
Brakujące wezwanie do zrobienia było moim problemem. Dziękuję za Twoją odpowiedź!
Marco Santarossa
1
Należy jednak pamiętać, że funkcje strzałek nie mają osobnego zakresu.
JepZ
19

To działało!

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
źródło
2
to najlepsza odpowiedź
Văn Quyết
13

Ten sam błąd występował podczas próby uruchomienia bardzo prostej kompilacji SASS / CSS .

Moim rozwiązaniem (które może rozwiązać te same lub podobne błędy) było po prostu dodanie donejako parametru w domyślnej funkcji zadania i wywołanie jej na końcu domyślnego zadania:

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

Mam nadzieję że to pomoże!

KLPA
źródło
7
Miło widzieć przykład z faktyczną zawartością zadania
Jonathan
8

Musisz zrobić dwie rzeczy:

  1. Dodaj asyncprzed funkcją.
  2. Rozpocznij swoją funkcję za pomocą return.

    var gulp = require('gulp');
    
    gulp.task('message', async function() {
        return console.log("HTTP Server Started");
    });
Majali
źródło
7

Nie mogę twierdzić, że mam dużą wiedzę na ten temat, ale miałem ten sam problem i go rozwiązałem.

Istnieje 7 sposób na rozwiązanie tego problemu, za pomocą funkcji asynchronicznej .

Napisz swoją funkcję, ale dodaj przedrostek asynchroniczny .

W ten sposób Gulp otacza funkcję obietnicą, a zadanie uruchomi się bez błędów.

Przykład:

async function() {
  // do something
};

Zasoby:

  1. Ostatni odcinek na Gulp strony Async Zakończenie : Korzystanie asynchroniczny / Oczekujcie .

  2. Dokumenty funkcji asynchronicznych Mozilli .

Jonny
źródło
7

Jest to problem podczas migracji z wersji gulp 3 do 4. Po prostu możesz dodać parametr zrobiony do funkcji oddzwaniania, patrz przykład,

   const gulp = require("gulp")

    gulp.task("message", function(done) {
      console.log("Gulp is running...")
      done()
    });
Moftah
źródło
5

Obejście: Musimy wywołać funkcje zwrotne (Zadanie i Anonimowy):

function electronTask(callbackA)
{
    return gulp.series(myFirstTask, mySeccondTask, (callbackB) =>
    {
        callbackA();
        callbackB();
    })();    
}
Jackes David Lemos
źródło
2

Proszę bardzo: brak synchronicznych zadań .

Brak synchronicznych zadań

Zadania synchroniczne nie są już obsługiwane. Często prowadziły do ​​subtelnych błędów, które były trudne do debugowania, takich jak zapomnienie o zwróceniu strumieni z zadania.

Kiedy zobaczysz Did you forget to signal async completion? ostrzeżenie, żadna z wyżej wymienionych technik nie została zastosowana. Aby rozwiązać problem, musisz użyć wywołania zwrotnego z pierwszym błędem lub zwrócić strumień, obietnicę, emiter zdarzeń, proces potomny lub obserwowalny.

Używanie async/await

Gdy nie używasz żadnej z poprzednich opcji, możesz zdefiniować swoje zadanie jako async function, które otacza twoje zadanie obietnicą . Pozwala to na synchroniczną pracę z obietnicami awaiti używanie innego kodu synchronicznego.

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
źródło
2

Zasadniczo wersja 3.X była prostsza, ale wersja 4.x jest rygorystyczna w przypadku tych zadań synchronicznych i asynchronicznych.

Asynchroniczny / Oczekujcie jest dość prosta i pomocny sposób zrozumieć workflow problem.

Użyj tego prostego podejścia

const gulp = require('gulp')

gulp.task('message',async function(){
return console.log('Gulp is running...')
})
Naveen Nirban Yadav
źródło
1

Miałem problemy z tym niedawno i znaleźć właściwą drogę, aby utworzyć defaultzadanie, które działa sasswtedy sass:watchbyło:

gulp.task('default', gulp.series('sass', 'sass:watch'));
Howard M. Lewis Ship
źródło
1

Moje rozwiązanie: umieść wszystko z asynchronizacją i czekaj na łyk.

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
źródło
0

Dodaj wykonane jako parametr w funkcji domyślnej. To wystarczy.

bmayur
źródło
0

Dla tych, którzy próbują użyć gulp do lokalnego wdrożenia swagger, pomoże następujący kod

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
źródło
0

Dla mnie problem był inny: Angular-cli nie został zainstalowany (zainstalowałem nową wersję Węzła za pomocą NVM i po prostu zapomniałem ponownie zainstalować Angular-cli)

Możesz sprawdzić uruchomienie „wersji”.

Jeśli go nie masz, po prostu uruchom „npm install -g @ angular / cli”

Ari Waisberg
źródło
0

Musisz zrobić jedną rzecz:

  • Dodaj asyncprzed funkcją.

const gulp = require('gulp');

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

Chinthani Sugandhika
źródło