Skip to content

Commit ad8b568

Browse files
janiceilenephated
authored andcommitted
Docs: Add "Async Completion" documentation
1 parent 50fafc6 commit ad8b568

File tree

1 file changed

+144
-0
lines changed

1 file changed

+144
-0
lines changed
+144
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
<!-- front-matter
2+
id: async-completion
3+
title: Async Completion
4+
hide_title: true
5+
sidebar_label: Async Completion
6+
-->
7+
8+
# Async Completion
9+
10+
Node libraries handle asynchronicity in a variety of ways. The most common pattern is [error-first callbacks][node-api-error-first-callbacks], but you might also encounter [streams][stream-docs], [promises][promise-docs], [event emitters][event-emitter-docs], [child processes][child-process-docs], or [observables][observable-docs]. Gulp tasks normalize all these types of asynchronicity.
11+
12+
## Signal task completion
13+
14+
When a stream, promise, event emitter, child process, or observable is returned from a task, the success or error informs gulp whether to continue or end. If a task errors, gulp will end immediately and show that error.
15+
16+
When composing tasks with `series()`, an error will end the composition and no further tasks will be executed. When composing tasks with `parallel()`, an error will end the composition but the other parallel tasks may or may not complete.
17+
18+
### Returning a stream
19+
20+
```js
21+
const { src, dest } = require('gulp');
22+
23+
function streamTask() {
24+
return src('*.js')
25+
.pipe(dest('output'));
26+
}
27+
28+
exports.default = streamTask;
29+
```
30+
31+
### Returning a promise
32+
33+
```js
34+
function promiseTask() {
35+
return Promise.resolve('some ignored value');
36+
}
37+
38+
exports.default = promiseTask;
39+
```
40+
41+
### Returning an event emitter
42+
43+
```js
44+
const { EventEmitter } = require('events');
45+
46+
function eventEmitterTask() {
47+
const emitter = new EventEmitter();
48+
// Emit has to happen async otherwise gulp isn't listening yet
49+
setTimeout(() => emitter.emit('finish'), 250);
50+
return emitter;
51+
}
52+
53+
exports.default = eventEmitterTask;
54+
```
55+
56+
### Returning a child process
57+
58+
```js
59+
const { exec } = require('child_process');
60+
61+
function childProcessTask() {
62+
return exec('date');
63+
}
64+
65+
exports.default = childProcessTask;
66+
```
67+
68+
### Returning an observable
69+
70+
```js
71+
const { Observable } = require('rxjs');
72+
73+
function observableTask() {
74+
return Observable.of(1, 2, 3);
75+
}
76+
77+
exports.default = observableTask;
78+
```
79+
80+
### Using an error-first callback
81+
82+
If nothing is returned from your task, you must use the error-first callback to signal completion. The callback will be passed to your task as the only argument - named `done()` in the examples below.
83+
84+
```js
85+
function callbackTask(done) {
86+
// `done()` should be called by some async work
87+
done();
88+
}
89+
90+
exports.default = callbackTask;
91+
```
92+
93+
To indicate to gulp that an error occurred in a task using an error-first callback, call it with an `Error` as the only argument.
94+
95+
```js
96+
function callbackError(done) {
97+
// `done()` should be called by some async work
98+
done(new Error('kaboom'));
99+
}
100+
101+
exports.default = callbackError;
102+
```
103+
104+
However, you'll often pass this callback to another API instead of calling it yourself.
105+
106+
```js
107+
const fs = require('fs');
108+
109+
function passingCallback(done) {
110+
fs.access('gulpfile.js', done);
111+
}
112+
113+
exports.default = passingCallback;
114+
```
115+
116+
## No synchronous tasks
117+
118+
Synchronous tasks are no longer supported. They often led to subtle mistakes that were hard to debug, like forgetting to return your streams from a task.
119+
120+
When you see the _"Did you forget to signal async completion?"_ warning, none of the techniques mentioned above were used. You'll need to use the error-first callback or return a stream, promise, event emitter, child process, or observable to resolve the issue.
121+
122+
## Using async/await
123+
124+
When not using any of the previous options, you can define your task as an [`async` function][async-await-docs], which wraps your task in a promise. This allows you to work with promises synchronously using `await` and use other synchronous code.
125+
126+
```js
127+
const fs = require('fs');
128+
129+
async function asyncAwaitTask() {
130+
const { version } = fs.readFileSync('package.json');
131+
console.log(version);
132+
await Promise.resolve('some result');
133+
}
134+
135+
exports.default = asyncAwaitTask;
136+
```
137+
138+
[node-api-error-first-callbacks]: https://nodejs.org/api/errors.html#errors_error_first_callbacks
139+
[stream-docs]: https://nodejs.org/api/stream.html#stream_stream
140+
[promise-docs]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises
141+
[event-emitter-docs]: https://nodejs.org/api/events.html#events_events
142+
[child-process-docs]: https://nodejs.org/api/child_process.html#child_process_child_process
143+
[observable-docs]: https://github.com/tc39/proposal-observable/blob/master/README.md
144+
[async-await-docs]: https://developers.google.com/web/fundamentals/primers/async-functions

0 commit comments

Comments
 (0)