lib: print to stdout/stderr directly instead of using console
This patch adds an internal function that prints to stdout or stderr by directly writing to the known file descriptor, and uses it internally in common cases to avoid the overhead of the console implementation. PR-URL: https://github.com/nodejs/node/pull/27320 Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
31b3dd2842
commit
2b24ffae22
20
lib/fs.js
20
lib/fs.js
@ -74,7 +74,8 @@ const {
|
||||
validateOffsetLengthRead,
|
||||
validateOffsetLengthWrite,
|
||||
validatePath,
|
||||
warnOnNonPortableTemplate
|
||||
warnOnNonPortableTemplate,
|
||||
handleErrorFromBinding
|
||||
} = require('internal/fs/utils');
|
||||
const {
|
||||
CHAR_FORWARD_SLASH,
|
||||
@ -117,23 +118,6 @@ function showTruncateDeprecation() {
|
||||
}
|
||||
}
|
||||
|
||||
function handleErrorFromBinding(ctx) {
|
||||
if (ctx.errno !== undefined) { // libuv error numbers
|
||||
const err = uvException(ctx);
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
Error.captureStackTrace(err, handleErrorFromBinding);
|
||||
throw err;
|
||||
}
|
||||
if (ctx.error !== undefined) { // Errors created in C++ land.
|
||||
// TODO(joyeecheung): currently, ctx.error are encoding errors
|
||||
// usually caused by memory problems. We need to figure out proper error
|
||||
// code(s) for this.
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
Error.captureStackTrace(ctx.error, handleErrorFromBinding);
|
||||
throw ctx.error;
|
||||
}
|
||||
}
|
||||
|
||||
function maybeCallback(cb) {
|
||||
if (typeof cb === 'function')
|
||||
return cb;
|
||||
|
@ -12,7 +12,8 @@ const {
|
||||
ERR_INVALID_OPT_VALUE_ENCODING,
|
||||
ERR_OUT_OF_RANGE
|
||||
},
|
||||
hideStackFrames
|
||||
hideStackFrames,
|
||||
uvException
|
||||
} = require('internal/errors');
|
||||
const {
|
||||
isUint8Array,
|
||||
@ -444,7 +445,26 @@ function warnOnNonPortableTemplate(template) {
|
||||
}
|
||||
}
|
||||
|
||||
// This handles errors following the convention of the fs binding.
|
||||
function handleErrorFromBinding(ctx) {
|
||||
if (ctx.errno !== undefined) { // libuv error numbers
|
||||
const err = uvException(ctx);
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
Error.captureStackTrace(err, handleErrorFromBinding);
|
||||
throw err;
|
||||
}
|
||||
if (ctx.error !== undefined) { // Errors created in C++ land.
|
||||
// TODO(joyeecheung): currently, ctx.error are encoding errors
|
||||
// usually caused by memory problems. We need to figure out proper error
|
||||
// code(s) for this.
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
Error.captureStackTrace(ctx.error, handleErrorFromBinding);
|
||||
throw ctx.error;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
handleErrorFromBinding,
|
||||
assertEncoding,
|
||||
copyObject,
|
||||
Dirent,
|
||||
|
@ -11,7 +11,7 @@ const {
|
||||
evalScript
|
||||
} = require('internal/process/execution');
|
||||
|
||||
const console = require('internal/console/global');
|
||||
const { print, kStderr, kStdout } = require('internal/util/print');
|
||||
|
||||
const { getOptionValue } = require('internal/options');
|
||||
|
||||
@ -21,14 +21,12 @@ markBootstrapComplete();
|
||||
|
||||
// --input-type flag not supported in REPL
|
||||
if (getOptionValue('--input-type')) {
|
||||
// If we can't write to stderr, we'd like to make this a noop,
|
||||
// so use console.error.
|
||||
console.error('Cannot specify --input-type for REPL');
|
||||
print(kStderr, 'Cannot specify --input-type for REPL');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`Welcome to Node.js ${process.version}.\n` +
|
||||
'Type ".help" for more information.');
|
||||
print(kStdout, `Welcome to Node.js ${process.version}.\n` +
|
||||
'Type ".help" for more information.');
|
||||
|
||||
const cliRepl = require('internal/repl');
|
||||
cliRepl.createInternalRepl(process.env, (err, repl) => {
|
||||
|
@ -35,26 +35,24 @@ function tryGetCwd() {
|
||||
}
|
||||
}
|
||||
|
||||
function evalModule(source, print) {
|
||||
const { log, error } = require('internal/console/global');
|
||||
function evalModule(source, printResult) {
|
||||
const { decorateErrorStack } = require('internal/util');
|
||||
const asyncESM = require('internal/process/esm_loader');
|
||||
const { kStdout, kStderr, print } = require('internal/util/print');
|
||||
asyncESM.loaderPromise.then(async (loader) => {
|
||||
const { result } = await loader.eval(source);
|
||||
if (print) {
|
||||
log(result);
|
||||
}
|
||||
if (printResult) { print(kStdout, result); }
|
||||
})
|
||||
.catch((e) => {
|
||||
decorateErrorStack(e);
|
||||
error(e);
|
||||
print(kStderr, e);
|
||||
process.exit(1);
|
||||
});
|
||||
// Handle any nextTicks added in the first tick of the program.
|
||||
process._tickCallback();
|
||||
}
|
||||
|
||||
function evalScript(name, body, breakFirstLine, print) {
|
||||
function evalScript(name, body, breakFirstLine, printResult) {
|
||||
const CJSModule = require('internal/modules/cjs/loader');
|
||||
const { kVmBreakFirstLineSymbol } = require('internal/util');
|
||||
|
||||
@ -79,9 +77,9 @@ function evalScript(name, body, breakFirstLine, print) {
|
||||
[kVmBreakFirstLineSymbol]: ${!!breakFirstLine}
|
||||
});\n`;
|
||||
const result = module._compile(script, `${name}-wrapper`);
|
||||
if (print) {
|
||||
const { log } = require('internal/console/global');
|
||||
log(result);
|
||||
if (printResult) {
|
||||
const { kStdout, print } = require('internal/util/print');
|
||||
print(kStdout, result);
|
||||
}
|
||||
// Handle any nextTicks added in the first tick of the program.
|
||||
process._tickCallback();
|
||||
|
67
lib/internal/util/print.js
Normal file
67
lib/internal/util/print.js
Normal file
@ -0,0 +1,67 @@
|
||||
'use strict';
|
||||
|
||||
// This implements a light-weight printer that writes to stdout/stderr
|
||||
// directly to avoid the overhead in the console abstraction.
|
||||
|
||||
const { formatWithOptions } = require('internal/util/inspect');
|
||||
const { writeString } = internalBinding('fs');
|
||||
const { handleErrorFromBinding } = require('internal/fs/utils');
|
||||
const { guessHandleType } = internalBinding('util');
|
||||
const { log } = require('internal/console/global');
|
||||
|
||||
const kStdout = 1;
|
||||
const kStderr = 2;
|
||||
const handleType = [undefined, undefined, undefined];
|
||||
function getFdType(fd) {
|
||||
if (handleType[fd] === undefined) {
|
||||
handleType[fd] = guessHandleType(fd);
|
||||
}
|
||||
return handleType[fd];
|
||||
}
|
||||
|
||||
function formatAndWrite(fd, obj, ignoreErrors, colors = false) {
|
||||
const str = `${formatWithOptions({ colors }, obj)}\n`;
|
||||
const ctx = {};
|
||||
writeString(fd, str, null, undefined, undefined, ctx);
|
||||
if (!ignoreErrors) {
|
||||
handleErrorFromBinding(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
let colors;
|
||||
function getColors() {
|
||||
if (colors === undefined) {
|
||||
colors = require('internal/tty').getColorDepth() > 2;
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
|
||||
// TODO(joyeecheung): replace more internal process._rawDebug()
|
||||
// and console.log() usage with this if possible.
|
||||
function print(fd, obj, ignoreErrors = true) {
|
||||
switch (getFdType(fd)) {
|
||||
case 'TTY':
|
||||
formatAndWrite(fd, obj, ignoreErrors, getColors());
|
||||
break;
|
||||
case 'FILE':
|
||||
formatAndWrite(fd, obj, ignoreErrors);
|
||||
break;
|
||||
case 'PIPE':
|
||||
case 'TCP':
|
||||
// Fallback to console.log to handle IPC.
|
||||
if (process.channel && process.channel.fd === fd) {
|
||||
log(obj);
|
||||
} else {
|
||||
formatAndWrite(fd, obj, ignoreErrors);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log(obj);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
print,
|
||||
kStderr,
|
||||
kStdout
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user