4.2 Print

Overview

Let's begin by exploring one of the most straightforward and frequently employed external references in Deno: printing. According to the ECMAScript specification, there isn't a predefined function known as console.log. The availability of this function depends on the particular implementation, so it's up to the user to handle it. The V8 engine does offer some logging capabilities, but these are primarily focused on the inner workings of the core engine itself. Unfortunately, V8 does not extend its support to user-level logging, including the widely used console.log function. The widely used console.log function is implemented externally in Deno, meaning that Deno itself provides this functionality. This function allows you to display messages and information in the terminal or console while you are running your Deno programs.

Function

Registration

The registration of the print function happens at the startup:
pub fn op_print(#[string] msg: &str, is_err: bool) -> Result<(), Error> {
The op_print function stands as an inherent operation within Deno's framework. Similar to other operations (ops), this function is enlisted as an external reference.

JS space

Let's see how console.log is implemented in JS space. The function console.log T
comes from the console class:
const windowOrWorkerGlobalScope = {
// -- CODE OMITTED --
console: util.nonEnumerable(
new console.Console((msg, level) => core.print(msg, level > 1)),
)
// -- CODE OMITTED --
}
Let's take a look at how console.log is implemented in Deno. It's worth noting that the printFunc used here is essentially the same as core.print.
log = (...args) => {
this.#printFunc(
inspectArgs(args, {
...getConsoleInspectOptions(),
indentLevel: this.indentLevel,
}) + "\n",
1,
);
};
The core.print simply invokes op_print API:
print: (msg, isErr) => ops.op_print(msg, isErr),

Rust space

The op_print function serves as a fundamental tool within Deno, employing Rust's standard APIs to facilitate the printing of data onto the console. By harnessing the capabilities of Rust's std library, this function becomes the ultimate method for displaying information to the user through the console interface.
pub fn op_print(#[string] msg: &str, is_err: bool) -> Result<(), Error> {
if is_err {
stderr().write_all(msg.as_bytes())?;
stderr().flush().unwrap();
} else {
stdout().write_all(msg.as_bytes())?;
stdout().flush().unwrap();
}
Ok(())
}
Here, we have a straightforward function at play. Its primary task is to take some data as input and transform it into bytes. Once this transformation is complete, the function proceeds to send these bytes to the standard output or standard error, depending on the nature of the data.