Skip to content

Commit 10a497c

Browse files
sam-githubMylesBorins
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 <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Jeremiah Senkpiel <[email protected]>
1 parent 53d5002 commit 10a497c

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
@@ -880,10 +880,11 @@ added: v0.1.13
880880

881881
* `code` {Integer} The exit code. Defaults to `0`.
882882

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

888889
To exit with a 'failure' code:
889890

@@ -916,7 +917,7 @@ if (someConditionNotMet()) {
916917
```
917918

918919
The reason this is problematic is because writes to `process.stdout` in Node.js
919-
are sometimes *non-blocking* and may occur over multiple ticks of the Node.js
920+
are sometimes *asynchronous* and may occur over multiple ticks of the Node.js
920921
event loop. Calling `process.exit()`, however, forces the process to exit
921922
*before* those additional writes to `stdout` can be performed.
922923

@@ -1511,23 +1512,11 @@ Android)
15111512

15121513
* {Stream}
15131514

1514-
The `process.stderr` property returns a [Writable][] stream equivalent to or
1515-
associated with `stderr` (fd `2`).
1515+
The `process.stderr` property returns a [Writable][] stream connected to
1516+
`stderr` (fd `2`).
15161517

1517-
Note: `process.stderr` and `process.stdout` differ from other Node.js streams
1518-
in several ways:
1519-
1. They cannot be closed ([`end()`][] will throw).
1520-
2. They never emit the [`'finish'`][] event.
1521-
3. Writes _can_ block when output is redirected to a file.
1522-
- Note that disks are fast and operating systems normally employ write-back
1523-
caching so this is very uncommon.
1524-
4. Writes on UNIX **will** block by default if output is going to a TTY
1525-
(a terminal).
1526-
5. Windows functionality differs. Writes block except when output is going to a
1527-
TTY.
1528-
1529-
To check if Node.js is being run in a TTY context, read the `isTTY` property
1530-
on `process.stderr`, `process.stdout`, or `process.stdin`:
1518+
Note: `process.stderr` differs from other Node.js streams in important ways,
1519+
see [note on process I/O][] for more information.
15311520

15321521
## process.stdin
15331522

@@ -1565,48 +1554,59 @@ must call `process.stdin.resume()` to read from it. Note also that calling
15651554

15661555
* {Stream}
15671556

1568-
The `process.stdout` property returns a [Writable][] stream equivalent to or
1569-
associated with `stdout` (fd `1`).
1557+
The `process.stdout` property returns a [Writable][] stream connected to
1558+
`stdout` (fd `2`).
15701559

1571-
For example:
1560+
For example, to copy process.stdin to process.stdout:
15721561

15731562
```js
1574-
console.log = (msg) => {
1575-
process.stdout.write(`${msg}\n`);
1576-
};
1563+
process.stdin.pipe(process.stdout);
15771564
```
15781565

1579-
Note: `process.stderr` and `process.stdout` differ from other Node.js streams
1580-
in several ways:
1581-
1. They cannot be closed ([`end()`][] will throw).
1582-
2. They never emit the [`'finish'`][] event.
1583-
3. Writes _can_ block when output is redirected to a file.
1584-
- Note that disks are fast and operating systems normally employ write-back
1585-
caching so this is very uncommon.
1586-
4. Writes on UNIX **will** block by default if output is going to a TTY
1587-
(a terminal).
1588-
5. Windows functionality differs. Writes block except when output is going to a
1589-
TTY.
1566+
Note: `process.stdout` differs from other Node.js streams in important ways,
1567+
see [note on process I/O][] for more information.
1568+
1569+
### A note on process I/O
15901570

1591-
To check if Node.js is being run in a TTY context, read the `isTTY` property
1592-
on `process.stderr`, `process.stdout`, or `process.stdin`:
1571+
`process.stdout` and `process.stderr` differ from other Node.js streams in
1572+
important ways:
15931573

1594-
### TTY Terminals and `process.stdout`
1574+
1. They are used internally by [`console.log()`][] and [`console.error()`][],
1575+
respectively.
1576+
2. They cannot be closed ([`end()`][] will throw).
1577+
3. They will never emit the [`'finish'`][] event.
1578+
4. Writes may be synchronous depending on the what the stream is connected to
1579+
and whether the system is Windows or Unix:
1580+
- Files: *synchronous* on Windows and Linux
1581+
- TTYs (Terminals): *asynchronous* on Windows, *synchronous* on Unix
1582+
- Pipes (and sockets): *synchronous* on Windows, *asynchronous* on Unix
15951583

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

1600-
To check if Node.js is being run in a [TTY][] context, check the `isTTY`
1601-
property on `process.stderr`, `process.stdout`, or `process.stdin`.
1587+
Synchronous writes avoid problems such as output written with `console.log()` or
1588+
`console.write()` being unexpectedly interleaved, or not written at all if
1589+
`process.exit()` is called before an asynchronous write completes. See
1590+
[`process.exit()`][] for more information.
1591+
1592+
***Warning***: Synchronous writes block the event loop until the write has
1593+
completed. This can be near instantaneous in the case of output to a file, but
1594+
under high system load, pipes that are not being read at the receiving end, or
1595+
with slow terminals or file systems, its possible for the event loop to be
1596+
blocked often enough and long enough to have severe negative performance
1597+
impacts. This may not be a problem when writing to an interactive terminal
1598+
session, but consider this particularly careful when doing production logging to
1599+
the process output streams.
1600+
1601+
To check if a stream is connected to a [TTY][] context, check the `isTTY`
1602+
property.
16021603

16031604
For instance:
16041605
```console
16051606
$ node -p "Boolean(process.stdin.isTTY)"
16061607
true
16071608
$ echo "foo" | node -p "Boolean(process.stdin.isTTY)"
16081609
false
1609-
16101610
$ node -p "Boolean(process.stdout.isTTY)"
16111611
true
16121612
$ node -p "Boolean(process.stdout.isTTY)" | cat
@@ -1758,6 +1758,7 @@ cases:
17581758
the high-order bit, and then contain the value of the signal code.
17591759

17601760

1761+
[`'exit'`]: #process_event_exit
17611762
[`'finish'`]: stream.html#stream_event_finish
17621763
[`'message'`]: child_process.html#child_process_event_message
17631764
[`'rejectionHandled'`]: #process_event_rejectionhandled
@@ -1779,6 +1780,7 @@ cases:
17791780
[`promise.catch()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch
17801781
[`require.main`]: modules.html#modules_accessing_the_main_module
17811782
[`setTimeout(fn, 0)`]: timers.html#timers_settimeout_callback_delay_args
1783+
[note on process I/O]: process.html#process_a_note_on_process_i_o
17821784
[process_emit_warning]: #process_process_emitwarning_warning_name_ctor
17831785
[process_warning]: #process_event_warning
17841786
[Signal Events]: #process_signal_events

0 commit comments

Comments
 (0)