Skip to content

Commit 5ba00af

Browse files
committed
doc: describe when stdout/err is sync
process.stdout, process.stderr, and console.log() and console.error() which use the process streams, are usually synchronous. Warn about this, and clearly describe the conditions under which they are synchronous. Fix: #10617 PR-URL: #10884 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Jeremiah Senkpiel <[email protected]>
1 parent 00c86cc commit 5ba00af

File tree

2 files changed

+57
-64
lines changed

2 files changed

+57
-64
lines changed

doc/api/console.md

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,15 @@ The module exports two specific components:
99

1010
* A `Console` class with methods such as `console.log()`, `console.error()` and
1111
`console.warn()` that can be used to write to any Node.js stream.
12-
* A global `console` instance configured to write to `stdout` and `stderr`.
13-
Because this object is global, it can be used without calling
12+
* A global `console` instance configured to write to [`process.stdout`][] and
13+
[`process.stderr`][]. The global `console` can be used without calling
1414
`require('console')`.
1515

16+
***Warning***: The global console object's methods are neither consistently
17+
synchronous like the browser APIs they resemble, nor are they consistently
18+
asynchronous like all other Node.js streams. See the [note on process I/O][] for
19+
more information.
20+
1621
Example using the global `console`:
1722

1823
```js
@@ -47,21 +52,6 @@ myConsole.warn(`Danger ${name}! Danger!`);
4752
// Prints: Danger Will Robinson! Danger!, to err
4853
```
4954

50-
While the API for the `Console` class is designed fundamentally around the
51-
browser `console` object, the `Console` in Node.js is *not* intended to
52-
duplicate the browser's functionality exactly.
53-
54-
## Asynchronous vs Synchronous Consoles
55-
56-
The console functions are usually asynchronous unless the destination is a file.
57-
Disks are fast and operating systems normally employ write-back caching;
58-
it should be a very rare occurrence indeed that a write blocks, but it
59-
is possible.
60-
61-
Additionally, console functions are blocking when outputting to TTYs
62-
(terminals) on OS X as a workaround for the OS's very small, 1kb buffer size.
63-
This is to prevent interleaving between `stdout` and `stderr`.
64-
6555
## Class: Console
6656

6757
<!--type=class-->
@@ -305,4 +295,5 @@ The `console.warn()` function is an alias for [`console.error()`][].
305295
[`util.format()`]: util.html#util_util_format_format_args
306296
[`util.inspect()`]: util.html#util_util_inspect_object_options
307297
[customizing `util.inspect()` colors]: util.html#util_customizing_util_inspect_colors
298+
[note on process I/O]: process.html#process_a_note_on_process_i_o
308299
[web-api-assert]: https://developer.mozilla.org/en-US/docs/Web/API/console/assert

doc/api/process.md

Lines changed: 49 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -859,10 +859,11 @@ added: v0.1.13
859859

860860
* `code` {Integer} The exit code. Defaults to `0`.
861861

862-
The `process.exit()` method instructs Node.js to terminate the process as
863-
quickly as possible with the specified exit `code`. If the `code` is omitted,
864-
exit uses either the 'success' code `0` or the value of `process.exitCode` if
865-
specified.
862+
The `process.exit()` method instructs Node.js to terminate the process
863+
synchronously with an exit status of `code`. If `code` is omitted, exit uses
864+
either the 'success' code `0` or the value of `process.exitCode` if it has been
865+
set. Node.js will not terminate until all the [`'exit'`] event listeners are
866+
called.
866867

867868
To exit with a 'failure' code:
868869

@@ -895,7 +896,7 @@ if (someConditionNotMet()) {
895896
```
896897

897898
The reason this is problematic is because writes to `process.stdout` in Node.js
898-
are sometimes *non-blocking* and may occur over multiple ticks of the Node.js
899+
are sometimes *asynchronous* and may occur over multiple ticks of the Node.js
899900
event loop. Calling `process.exit()`, however, forces the process to exit
900901
*before* those additional writes to `stdout` can be performed.
901902

@@ -1488,23 +1489,11 @@ Android)
14881489

14891490
* {Stream}
14901491

1491-
The `process.stderr` property returns a [Writable][] stream equivalent to or
1492-
associated with `stderr` (fd `2`).
1492+
The `process.stderr` property returns a [Writable][] stream connected to
1493+
`stderr` (fd `2`).
14931494

1494-
Note: `process.stderr` and `process.stdout` differ from other Node.js streams
1495-
in several ways:
1496-
1. They cannot be closed ([`end()`][] will throw).
1497-
2. They never emit the [`'finish'`][] event.
1498-
3. Writes _can_ block when output is redirected to a file.
1499-
- Note that disks are fast and operating systems normally employ write-back
1500-
caching so this is very uncommon.
1501-
4. Writes on UNIX **will** block by default if output is going to a TTY
1502-
(a terminal).
1503-
5. Windows functionality differs. Writes block except when output is going to a
1504-
TTY.
1505-
1506-
To check if Node.js is being run in a TTY context, read the `isTTY` property
1507-
on `process.stderr`, `process.stdout`, or `process.stdin`:
1495+
Note: `process.stderr` differs from other Node.js streams in important ways,
1496+
see [note on process I/O][] for more information.
15081497

15091498
## process.stdin
15101499

@@ -1542,48 +1531,59 @@ must call `process.stdin.resume()` to read from it. Note also that calling
15421531

15431532
* {Stream}
15441533

1545-
The `process.stdout` property returns a [Writable][] stream equivalent to or
1546-
associated with `stdout` (fd `1`).
1534+
The `process.stdout` property returns a [Writable][] stream connected to
1535+
`stdout` (fd `2`).
15471536

1548-
For example:
1537+
For example, to copy process.stdin to process.stdout:
15491538

15501539
```js
1551-
console.log = (msg) => {
1552-
process.stdout.write(`${msg}\n`);
1553-
};
1540+
process.stdin.pipe(process.stdout);
15541541
```
15551542

1556-
Note: `process.stderr` and `process.stdout` differ from other Node.js streams
1557-
in several ways:
1558-
1. They cannot be closed ([`end()`][] will throw).
1559-
2. They never emit the [`'finish'`][] event.
1560-
3. Writes _can_ block when output is redirected to a file.
1561-
- Note that disks are fast and operating systems normally employ write-back
1562-
caching so this is very uncommon.
1563-
4. Writes on UNIX **will** block by default if output is going to a TTY
1564-
(a terminal).
1565-
5. Windows functionality differs. Writes block except when output is going to a
1566-
TTY.
1543+
Note: `process.stdout` differs from other Node.js streams in important ways,
1544+
see [note on process I/O][] for more information.
1545+
1546+
### A note on process I/O
15671547

1568-
To check if Node.js is being run in a TTY context, read the `isTTY` property
1569-
on `process.stderr`, `process.stdout`, or `process.stdin`:
1548+
`process.stdout` and `process.stderr` differ from other Node.js streams in
1549+
important ways:
15701550

1571-
### TTY Terminals and `process.stdout`
1551+
1. They are used internally by [`console.log()`][] and [`console.error()`][],
1552+
respectively.
1553+
2. They cannot be closed ([`end()`][] will throw).
1554+
3. They will never emit the [`'finish'`][] event.
1555+
4. Writes may be synchronous depending on the what the stream is connected to
1556+
and whether the system is Windows or Unix:
1557+
- Files: *synchronous* on Windows and Linux
1558+
- TTYs (Terminals): *asynchronous* on Windows, *synchronous* on Unix
1559+
- Pipes (and sockets): *synchronous* on Windows, *asynchronous* on Unix
15721560

1573-
The `process.stderr` and `process.stdout` streams are blocking when outputting
1574-
to TTYs (terminals) on OS X as a workaround for the operating system's small,
1575-
1kb buffer size. This is to prevent interleaving between `stdout` and `stderr`.
1561+
These behaviours are partly for historical reasons, as changing them would
1562+
create backwards incompatibility, but they are also expected by some users.
15761563

1577-
To check if Node.js is being run in a [TTY][] context, check the `isTTY`
1578-
property on `process.stderr`, `process.stdout`, or `process.stdin`.
1564+
Synchronous writes avoid problems such as output written with `console.log()` or
1565+
`console.write()` being unexpectedly interleaved, or not written at all if
1566+
`process.exit()` is called before an asynchronous write completes. See
1567+
[`process.exit()`][] for more information.
1568+
1569+
***Warning***: Synchronous writes block the event loop until the write has
1570+
completed. This can be near instantaneous in the case of output to a file, but
1571+
under high system load, pipes that are not being read at the receiving end, or
1572+
with slow terminals or file systems, its possible for the event loop to be
1573+
blocked often enough and long enough to have severe negative performance
1574+
impacts. This may not be a problem when writing to an interactive terminal
1575+
session, but consider this particularly careful when doing production logging to
1576+
the process output streams.
1577+
1578+
To check if a stream is connected to a [TTY][] context, check the `isTTY`
1579+
property.
15791580

15801581
For instance:
15811582
```console
15821583
$ node -p "Boolean(process.stdin.isTTY)"
15831584
true
15841585
$ echo "foo" | node -p "Boolean(process.stdin.isTTY)"
15851586
false
1586-
15871587
$ node -p "Boolean(process.stdout.isTTY)"
15881588
true
15891589
$ node -p "Boolean(process.stdout.isTTY)" | cat
@@ -1737,6 +1737,7 @@ cases:
17371737
the high-order bit, and then contain the value of the signal code.
17381738

17391739

1740+
[`'exit'`]: #process_event_exit
17401741
[`'finish'`]: stream.html#stream_event_finish
17411742
[`'message'`]: child_process.html#child_process_event_message
17421743
[`'rejectionHandled'`]: #process_event_rejectionhandled
@@ -1758,6 +1759,7 @@ cases:
17581759
[`promise.catch()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch
17591760
[`require.main`]: modules.html#modules_accessing_the_main_module
17601761
[`setTimeout(fn, 0)`]: timers.html#timers_settimeout_callback_delay_args
1762+
[note on process I/O]: process.html#process_a_note_on_process_i_o
17611763
[process_emit_warning]: #process_process_emitwarning_warning_name_ctor
17621764
[process_warning]: #process_event_warning
17631765
[Signal Events]: #process_signal_events

0 commit comments

Comments
 (0)