4.2 Print

Overview

Let's begin by exploring one of the most straightforward and quite frequently used external reference in Deno: printing data. 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 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 is a basic tool in Deno that uses Rust's standard APIs to print data to the console. By using Rust's std library, this function provides the simplest way to display information to the user through the console.

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.

Last updated