How to use async/await with Gulp 4?

glen-84 picture glen-84 · Dec 9, 2015 · Viewed 9.8k times · Source

I'm trying to do something like this:

gulp.task("test", async () => {
    return gulp.src("**/*.scss")
        .pipe(print((filePath) => `File: ${filePath}`));
});

(print is gulp-print)

But it gives the following:

[22:08:43] Starting 'test'...
[22:08:43] Finished 'test' after 12 ms
[22:08:43] File: src\app\styles\app.scss
[22:08:43] File: src\app\styles\test.scss

i.e. It finishes before the messages are printed.

I'm using Gulp 4 (alpha 2 I think) and TypeScript (1.8.0-dev.20151204).

The generated (ES6) code looks like this:

gulp.task("test", () => __awaiter(this, void 0, Promise, function* () {
    return gulp.src("**/*.scss")
        .pipe(print((filePath) => `File: ${filePath}`));
}));

Where __awaiter is:

var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promise, generator) {
    return new Promise(function (resolve, reject) {
        generator = generator.call(thisArg, _arguments);
        function cast(value) { return value instanceof Promise && value.constructor === Promise ? value : new Promise(function (resolve) { resolve(value); }); }
        function onfulfill(value) { try { step("next", value); } catch (e) { reject(e); } }
        function onreject(value) { try { step("throw", value); } catch (e) { reject(e); } }
        function step(verb, value) {
            var result = generator[verb](value);
            result.done ? resolve(result.value) : cast(result.value).then(onfulfill, onreject);
        }
        step("next", void 0);
    });
};

Is it possible to get this working? I want to use await within my task function, but I can't do this without marking the function as asynchronous.

I'm probably missing something obvious.

Answer

glen-84 picture glen-84 · Dec 10, 2015

I was able to get this working with help from here and here.

gulp.task("test", async () => {
    await new Promise((resolve, reject) => {
        gulp.src("**/*.scss")
            .pipe(print((filePath) => `File: ${filePath}`))
            .on("end", resolve);
    });
});

In my real task, I had to use the finish event instead of the end event (see the 2nd link above).

It's not crystal-clear how this all works, but I think it's something along the lines of:

  1. Gulp functions are async, so they need to be awaited, but since they aren't promises, you have to wrap them in one.
  2. In order to resolve the promise, you need to listen to either the end or the finish event, and which one depends on what the last pipe returns.

Another option that appears to work is resume() followed by on("end"), in cases where finish is usually needed. This is probably because of this. I'm not sure which option is better.

I would love to understand this more, so if you're able to explain this in simple terms, please feel free to comment or post an answer.

Edit: You can also return the promise, instead of awaiting it.