Standard Library: Console, URL & Timers

This section documents modern ECMAScript and core browser JavaScript APIs — it is not tied to any specific framework or library (React, Vue, Angular, etc.). This content was generated with the assistance of AI and should be verified against the current ECMAScript specification and MDN documentation before relying on it in production, since JavaScript language features and browser API support continue to evolve.

This section’s bibliography lists the reference material consulted while preparing these pages.

Beyond collections, regular expressions, and dates, JavaScript’s standard library ships a handful of everyday utilities that show up in almost every program: richer console output than a plain console.log(), a URL class for parsing and building URLs without hand-rolled string manipulation, and the timer functions that schedule code to run later. None of these are part of the core ECMAScript language specification — they are defined by the browser/Node host environment and the WHATWG — but they are supported everywhere and are, in practice, part of every JavaScript developer’s toolkit.

The Console API Beyond console.log()

console.log() is the function most developers reach for first, but the Console API (standardized by WHATWG) defines several other functions that are worth knowing:

Function Purpose

console.debug() / console.info() / console.warn() / console.error()

Aliases of console.log() with a different severity level. Browser dev tools typically prefix each with an icon and let you filter the console by level; in Node, console.error() writes to stderr instead of stdout.

console.assert(condition, …​args)

Logs …​args (prefixed with "Assertion failed") only when condition is falsy. Unlike a typical assert(), it never throws.

console.table(data, columns?)

Renders an array of same-shaped objects as a table, one row per object and one column per property. An optional second argument restricts which properties become columns.

console.trace(…​args)

Logs like console.log(), then appends a stack trace — useful for finding who called a function.

console.count(label) / console.countReset(label)

Logs label followed by how many times it has been called with that label; handy for counting how often an event handler fires. countReset() zeroes the counter.

console.group(label) / console.groupCollapsed(label) / console.groupEnd()

Indents every subsequent console message until the matching groupEnd(), visually nesting related log output. Browser dev tools let a group (or a groupCollapsed() group, collapsed by default) be expanded and collapsed as a unit.

console.time(label) / console.timeLog(label) / console.timeEnd(label)

Starts a named timer, optionally logs the elapsed time so far without stopping it, then logs the final elapsed time and stops the timer.

console.clear()

Clears the console, where the environment supports it (browsers, and Node when writing to a terminal rather than a redirected file/pipe).

console.table([
  { name: "Alice", role: "admin" },
  { name: "Bob", role: "editor" },
]);

console.group("Fetching user");
console.log("Sending request...");
console.log("Response received");
console.groupEnd();

console.time("parse");
// ... expensive work ...
console.timeEnd("parse"); // => "parse: 12.4ms"

Formatted output

When the first argument to a logging function is a string containing %s, %i/%d, %f, %o/%O, or %c, it is treated as a format string and subsequent arguments are substituted in:

console.log("%s scored %d points", "Alice", 42); // => "Alice scored 42 points"
console.log("%o", { a: 1, b: 2 });                // interactive object inspector
console.log("%cStyled text", "color: red; font-weight: bold"); // browsers only

This is rarely necessary in practice — passing values directly to console.log() and letting the environment format them (including an Error object’s stack trace) is usually good enough.

URL APIs

The URL class parses, reads, and mutates URLs correctly, including the escaping rules for each URL component — far more reliably than assembling URL strings by hand.

let url = new URL("https://example.com:8000/path/name?q=term#fragment");
url.href      // => "https://example.com:8000/path/name?q=term#fragment"
url.origin    // => "https://example.com:8000" (read-only)
url.protocol  // => "https:"
url.host      // => "example.com:8000"
url.hostname  // => "example.com"
url.port      // => "8000"
url.pathname  // => "/path/name"
url.search    // => "?q=term"
url.hash      // => "#fragment"

A second, base-URL argument resolves a relative URL: new URL("/api", "https://example.com"). Every property except origin is read/write, and assigning one automatically escapes special characters:

let url = new URL("https://example.com");
url.pathname = "path with spaces";
url.search = "q=foo#bar";
url.pathname // => "/path%20with%20spaces"
url.search   // => "?q=foo%23bar"

URLSearchParams

The search property is a plain read/write string for the whole query portion of the URL. When you need to work with individual name=value query parameters — including repeated names — use the read-only searchParams property instead, which returns a URLSearchParams object:

let url = new URL("https://example.com/search");
url.searchParams.append("q", "term");
url.searchParams.append("opts", "1");
url.searchParams.append("opts", "&"); // same name can repeat
url.searchParams.get("opts")     // => "1" (the first value)
url.searchParams.getAll("opts")  // => ["1", "&"]
url.searchParams.has("q")        // => true
url.searchParams.set("q", "x");  // replace the value
url.searchParams.sort();         // alphabetize parameters
[...url.searchParams]            // => iterable: [["opts", "1"], ["opts", "&"], ["q", "x"]]
url.searchParams.delete("opts");

A URLSearchParams can also be built standalone and assigned to search:

let params = new URLSearchParams();
params.append("q", "term");
params.append("opts", "exact");
let url = new URL("https://example.com");
url.search = params;
url.href // => "https://example.com/?q=term&opts=exact"

Legacy encode/decode functions

Before the URL class existed, JavaScript relied on global escape()/unescape() (deprecated, do not use) and then encodeURI()/decodeURI() plus encodeURIComponent()/decodeURIComponent(). The latter pair is still common for escaping a single value that will be inserted into a URL (e.g. a query-parameter value), since it escapes separator characters (/, ?, #) that encodeURI() deliberately leaves alone. For building or parsing whole URLs, prefer the URL class over any of these legacy functions — it applies the correct encoding per URL component instead of one scheme for the whole string.

Timers

setTimeout() and setInterval() are not part of the ECMAScript language itself, but every JavaScript host environment (browsers and Node) implements them, making them a de facto part of the standard library.

setTimeout(() => console.log("Ready..."), 1000);
setTimeout(() => console.log("set..."), 2000);
setTimeout(() => console.log("go!"), 3000);

setTimeout(fn, delay) schedules fn to run once, after at least delay milliseconds (it may run later if the event loop is busy) — it returns immediately, without blocking. Omitting delay (or passing 0) does not run fn immediately; it queues fn to run "as soon as possible" once the current call stack clears. setInterval() takes the same two arguments but re-invokes fn every delay milliseconds until cancelled.

Both functions return an opaque handle — a number in browsers, an object in Node — which can be passed to clearTimeout() or clearInterval() to cancel a pending or repeating call:

let clock = setInterval(() => {
  console.clear();
  console.log(new Date().toLocaleTimeString());
}, 1000);

setTimeout(() => clearInterval(clock), 10000); // stop after 10 seconds

queueMicrotask()

queueMicrotask(fn) schedules fn to run as a microtask — after the current synchronous code finishes, but before the event loop processes the next macrotask (a timer callback, an I/O event, or a rendering pass), and before any setTimeout(fn, 0) callback. It is the same queue that Promise callbacks use. Reach for it when you need to defer work briefly (e.g. to let a synchronous caller finish, or to batch multiple synchronous mutations before reacting to them) without the minimum-delay overhead setTimeout incurs. See Asynchronous JavaScript for how the microtask queue relates to promise resolution and the call stack.