Skip to content

Commit 5f1a568

Browse files
sam-githubitaloacasas
authored andcommitted
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 <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
1 parent 86a6478 commit 5f1a568

File tree

2 files changed

+57
-64
lines changed

2 files changed

+57
-64
lines changed

doc/api/console.md

+8-17
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

+49-47
Original file line numberDiff line numberDiff line change
@@ -850,10 +850,11 @@ added: v0.1.13
850850

851851
* `code` {Integer} The exit code. Defaults to `0`.
852852

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

858859
To exit with a 'failure' code:
859860

@@ -886,7 +887,7 @@ if (someConditionNotMet()) {
886887
```
887888

888889
The reason this is problematic is because writes to `process.stdout` in Node.js
889-
are sometimes *non-blocking* and may occur over multiple ticks of the Node.js
890+
are sometimes *asynchronous* and may occur over multiple ticks of the Node.js
890891
event loop. Calling `process.exit()`, however, forces the process to exit
891892
*before* those additional writes to `stdout` can be performed.
892893

@@ -1475,23 +1476,11 @@ Android)
14751476

14761477
* {Stream}
14771478

1478-
The `process.stderr` property returns a [Writable][] stream equivalent to or
1479-
associated with `stderr` (fd `2`).
1479+
The `process.stderr` property returns a [Writable][] stream connected to
1480+
`stderr` (fd `2`).
14801481

1481-
Note: `process.stderr` and `process.stdout` differ from other Node.js streams
1482-
in several ways:
1483-
1. They cannot be closed ([`end()`][] will throw).
1484-
2. They never emit the [`'finish'`][] event.
1485-
3. Writes _can_ block when output is redirected to a file.
1486-
- Note that disks are fast and operating systems normally employ write-back
1487-
caching so this is very uncommon.
1488-
4. Writes on UNIX **will** block by default if output is going to a TTY
1489-
(a terminal).
1490-
5. Windows functionality differs. Writes block except when output is going to a
1491-
TTY.
1492-
1493-
To check if Node.js is being run in a TTY context, read the `isTTY` property
1494-
on `process.stderr`, `process.stdout`, or `process.stdin`:
1482+
Note: `process.stderr` differs from other Node.js streams in important ways,
1483+
see [note on process I/O][] for more information.
14951484

14961485
## process.stdin
14971486

@@ -1529,48 +1518,59 @@ must call `process.stdin.resume()` to read from it. Note also that calling
15291518

15301519
* {Stream}
15311520

1532-
The `process.stdout` property returns a [Writable][] stream equivalent to or
1533-
associated with `stdout` (fd `1`).
1521+
The `process.stdout` property returns a [Writable][] stream connected to
1522+
`stdout` (fd `2`).
15341523

1535-
For example:
1524+
For example, to copy process.stdin to process.stdout:
15361525

15371526
```js
1538-
console.log = (msg) => {
1539-
process.stdout.write(`${msg}\n`);
1540-
};
1527+
process.stdin.pipe(process.stdout);
15411528
```
15421529

1543-
Note: `process.stderr` and `process.stdout` differ from other Node.js streams
1544-
in several ways:
1545-
1. They cannot be closed ([`end()`][] will throw).
1546-
2. They never emit the [`'finish'`][] event.
1547-
3. Writes _can_ block when output is redirected to a file.
1548-
- Note that disks are fast and operating systems normally employ write-back
1549-
caching so this is very uncommon.
1550-
4. Writes on UNIX **will** block by default if output is going to a TTY
1551-
(a terminal).
1552-
5. Windows functionality differs. Writes block except when output is going to a
1553-
TTY.
1530+
Note: `process.stdout` differs from other Node.js streams in important ways,
1531+
see [note on process I/O][] for more information.
1532+
1533+
### A note on process I/O
15541534

1555-
To check if Node.js is being run in a TTY context, read the `isTTY` property
1556-
on `process.stderr`, `process.stdout`, or `process.stdin`:
1535+
`process.stdout` and `process.stderr` differ from other Node.js streams in
1536+
important ways:
15571537

1558-
### TTY Terminals and `process.stdout`
1538+
1. They are used internally by [`console.log()`][] and [`console.error()`][],
1539+
respectively.
1540+
2. They cannot be closed ([`end()`][] will throw).
1541+
3. They will never emit the [`'finish'`][] event.
1542+
4. Writes may be synchronous depending on the what the stream is connected to
1543+
and whether the system is Windows or Unix:
1544+
- Files: *synchronous* on Windows and Linux
1545+
- TTYs (Terminals): *asynchronous* on Windows, *synchronous* on Unix
1546+
- Pipes (and sockets): *synchronous* on Windows, *asynchronous* on Unix
15591547

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

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

15671568
For instance:
15681569
```console
15691570
$ node -p "Boolean(process.stdin.isTTY)"
15701571
true
15711572
$ echo "foo" | node -p "Boolean(process.stdin.isTTY)"
15721573
false
1573-
15741574
$ node -p "Boolean(process.stdout.isTTY)"
15751575
true
15761576
$ node -p "Boolean(process.stdout.isTTY)" | cat
@@ -1724,6 +1724,7 @@ cases:
17241724
the high-order bit, and then contain the value of the signal code.
17251725

17261726

1727+
[`'exit'`]: #process_event_exit
17271728
[`'finish'`]: stream.html#stream_event_finish
17281729
[`'message'`]: child_process.html#child_process_event_message
17291730
[`'rejectionHandled'`]: #process_event_rejectionhandled
@@ -1745,6 +1746,7 @@ cases:
17451746
[`promise.catch()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch
17461747
[`require.main`]: modules.html#modules_accessing_the_main_module
17471748
[`setTimeout(fn, 0)`]: timers.html#timers_settimeout_callback_delay_args
1749+
[note on process I/O]: process.html#process_a_note_on_process_i_o
17481750
[process_emit_warning]: #process_process_emitwarning_warning_name_ctor
17491751
[process_warning]: #process_event_warning
17501752
[Signal Events]: #process_signal_events

0 commit comments

Comments
 (0)