This is a little-known way to console log without newline that many developers have never used.
Let’s say we need to log in a loop like this:
for (let i = 1; i <= 5; i++) {
// print number without newline
}
// Output: 1 2 3 4 5
❌ Unfortunately the normal way fails us:
So what do we do?
What we do: is process.stdout.write
:
for (let i = 1; i <= 5; i++) {
process.stdout.write(`${i} `);
}
// Output: 1 2 3 4 5
How is process.stdout.write
different from console.log
?
Well first of all, console.log
IS process.stdout.write
!
stdout
is the fundamental way every CLI program logs output to the console.
That’s what it uses at its core:
Console.prototype.log = function() {
this._stdout.write(util.format.apply(this, arguments) + '\n');
};
But this extra processing makes it so much better for formatting:
- I can easily inspect objects with
console.log
withoutJSON.stringify
:
But process.stdout.write
fails miserably — it only accepts strings and Buffers:
But there’s something incredible only process.stdout.write
can do:
Data streaming:
process.stdout
is actually, a stream.
Streams represent data flow in Node.
- Read streams — data coming from
- Write streams — data going into
- Duplex streams — both
Data’s flowing from the file read stream into the stdout stream.
It’s the same as this:
import fs from 'fs';
fs.createReadStream('codingbeautydev.txt').on(
'data',
(chunk) => {
process.stdout.write(chunk);
}
);
But pipe
is much more natural for stream-to-stream data flow:
Letting you create powerful transformation pipelines like this:
import fs from 'fs';
import { Transform } from 'stream';
// ✅ duplex stream
const uppercase = new Transform({
transform(chunk, encoding, callback) {
callback(null, chunk.toString().toUpperCase());
},
});
fs.createReadStream('codingbeautydev.txt')
.pipe(uppercase)
.pipe(process.stdout);
process.stdin
process.stdin
is the process.stdout
‘s input counterpart — a readable stream for user input.
So see how with a single line I create a pipeline to reflect all my input to me:
process.stdin.pipe(process.stdout);
And when I insert the uppercase transformation into the pipeline:
import fs from 'fs';
import { Transform } from 'stream';
// ✅ duplex stream
const uppercase = new Transform({
transform(chunk, encoding, callback) {
callback(null, chunk.toString().toUpperCase());
},
});
process.stdin.pipe(uppercase).pipe(process.stdout);
process.stderr
Here to complete the standard stream trio.
console.log
→process.stdin
console.error
→process.stderr
Probably also defined this way in Node:
Console.prototype.error = function() {
this._stderr.write(util.format.apply(this, arguments) + '\n');
};
console.log('A normal log message');
console.error('An error message');
You can see the difference in the browser:
Although not much difference on Node:
These are 3 powerful streams that let you input, process, and output data creatively and intuitively.
Every Crazy Thing JavaScript Does
A captivating guide to the subtle caveats and lesser-known parts of JavaScript.