diff --git a/doc/api/cli.md b/doc/api/cli.md index 7ae38fbe77480d..4578c618f5d698 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -288,6 +288,17 @@ Path to the file used to store the persistent REPL history. The default path is to an empty string (`""` or `" "`) disables persistent REPL history. +### `NODE_TTY_UNSAFE_ASYNC=1` + + +When set to `1`, writes to `stdout` and `stderr` will be non-blocking and +asynchronous when outputting to a TTY on platforms which support async stdio. +Setting this will void any guarantee that stdio will not be interleaved or +dropped at program exit. **Use of this mode is not recommended.** + + [Buffer]: buffer.html#buffer_buffer [debugger]: debugger.html [REPL]: repl.html diff --git a/doc/api/process.md b/doc/api/process.md index b58a2f37e19cfe..df8dc095ea8ec6 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -880,10 +880,9 @@ if (someConditionNotMet()) { ``` The reason this is problematic is because writes to `process.stdout` in Node.js -are usually *non-blocking* and may occur over multiple ticks of the Node.js -event loop. -Calling `process.exit()`, however, forces the process to exit *before* those -additional writes to `stdout` can be performed. +are sometimes *non-blocking* and may occur over multiple ticks of the Node.js +event loop. Calling `process.exit()`, however, forces the process to exit +*before* those additional writes to `stdout` can be performed. Rather than calling `process.exit()` directly, the code *should* set the `process.exitCode` and allow the process to exit naturally by avoiding @@ -1451,15 +1450,20 @@ Android) The `process.stderr` property returns a [Writable][] stream equivalent to or associated with `stderr` (fd `2`). -`process.stderr` and `process.stdout` are unlike other streams in Node.js in -that they cannot be closed (calling [`end()`][] will throw an Error), they never -emit the [`'finish'`][] event, and writes can block when output is redirected to -a file (although disks are fast and operating systems normally employ write-back -caching so it should be a very rare occurrence indeed.) +Note: `process.stderr` and `process.stdout` differ from other Node.js streams +in several ways: +1. They cannot be closed ([`end()`][] will throw). +2. They never emit the [`'finish'`][] event. +3. Writes _can_ block when output is redirected to a file. + - Note that disks are fast and operating systems normally employ write-back + caching so this is very uncommon. +4. Writes on UNIX __will__ block by default if output is going to a TTY + (a terminal). +5. Windows functionality differs. Writes block except when output is going to a + TTY. -Additionally, `process.stderr` and `process.stdout` are blocking when outputting -to TTYs (terminals) on OS X as a workaround for the OS's very small, 1kb -buffer size. This is to prevent interleaving between `stdout` and `stderr`. +To check if Node.js is being run in a TTY context, read the `isTTY` property +on `process.stderr`, `process.stdout`, or `process.stdin`: ## process.stdin @@ -1504,11 +1508,17 @@ console.log = (msg) => { }; ``` -`process.stderr` and `process.stdout` are unlike other streams in Node.js in -that they cannot be closed (calling [`end()`][] will throw an Error), they never -emit the [`'finish'`][] event and that writes can block when output is -redirected to a file (although disks are fast and operating systems normally -employ write-back caching so it should be a very rare occurrence indeed.) +Note: `process.stderr` and `process.stdout` differ from other Node.js streams +in several ways: +1. They cannot be closed ([`end()`][] will throw). +2. They never emit the [`'finish'`][] event. +3. Writes _can_ block when output is redirected to a file. + - Note that disks are fast and operating systems normally employ write-back + caching so this is very uncommon. +4. Writes on UNIX __will__ block by default if output is going to a TTY + (a terminal). +5. Windows functionality differs. Writes block except when output is going to a + TTY. To check if Node.js is being run in a TTY context, read the `isTTY` property on `process.stderr`, `process.stdout`, or `process.stdin`: diff --git a/doc/node.1 b/doc/node.1 index bdc2c8ad008ae8..1ec0d0ea486b9a 100644 --- a/doc/node.1 +++ b/doc/node.1 @@ -194,6 +194,13 @@ Path to the file used to store the persistent REPL history. The default path is ~/.node_repl_history, which is overridden by this variable. Setting the value to an empty string ("" or " ") disables persistent REPL history. +.TP +.BR NODE_TTY_UNSAFE_ASYNC=1 +When set to 1, writes to stdout and stderr will be non-blocking and asynchronous +when outputting to a TTY on platforms which support async stdio. +Setting this will void any guarantee that stdio will not be interleaved or +dropped at program exit. \fBAvoid use.\fR + .SH RESOURCES AND DOCUMENTATION diff --git a/lib/tty.js b/lib/tty.js index fe0cc2e5219966..576144e4013064 100644 --- a/lib/tty.js +++ b/lib/tty.js @@ -48,12 +48,12 @@ function WriteStream(fd) { writable: true }); - // Prevents interleaved stdout/stderr output in OS X terminals. + // Prevents interleaved or dropped stdout/stderr output for terminals. // As noted in the following reference, local TTYs tend to be quite fast and // this behaviour has become expected due historical functionality on OS X, // even though it was originally intended to change in v1.0.2 (Libuv 1.2.1). // Ref: https://github.com/nodejs/node/pull/1771#issuecomment-119351671 - if (process.platform === 'darwin') this._handle.setBlocking(true); + this._handle.setBlocking(process.env.NODE_TTY_UNSAFE_ASYNC !== '1'); var winSize = []; var err = this._handle.getWindowSize(winSize);