Node.js Performance APIs: An Introduction | AppSignal Blog (2024)

Node.js offers a rich set of performance datathrough its APIs, similar to how modern web browsers expose performance metricsfor webpages.

With tools like the Performance Measurement API and the perf_hooks module inNode.js, you can gain insights into your application's performance from theserver's perspective, closely aligning with what the end user experiences.

In this article, the first of a two-part series about performance hooks, we'll explore how to approach performance optimization inNode.js. Along the way, we'll leverage Node's built-in timing APIs to enhance the efficiency of our application.

Let's get going!

Prerequisites

To follow along with this tutorial, you'll need a basicknowledge of Node.js and a recent version installed, preferably thelatest LTS.

Understanding Fundamental Node.js Performance API Concepts

Before diving into Node.js performance APIs, it's important to understandsome essential terms that frequently appear in discussions and documentation: a monotonic clock, high resolution time API, and performance timeline. Let's look at each of these in turn.

1. A Monotonic Clock

In JavaScript, the Date.now() function generates timestamps based on thesystem clock, counting from the Unix epoch (1970-01-01T00:00:00Z). However,using these timestamps for precise measurements can be unreliable because theyare vulnerable to any alterations in the system clock.

In contrast, amonotonic clock offers atimekeeping mechanism that always progresses forward, without any backwardmovement. Its key advantage lies in its stability against system clock changes,making it ideal for accurately measuring the time span between events or theduration of specific tasks.

2. High Resolution Time API

The High Resolution Time API provides aJavaScript interface for obtaining highly accurate time measurements. It uses asub-millisecond monotonic timestamp that remains unaffected by any changes tothe system clock.

This API's functionality is encapsulated in the performance.now() method. Itreturns a timestamp in sub-milliseconds, calculated relative toperformance.timeOrigin — a UNIX timestamp denoting the initiation of a currentNode.js process.

Here's a quick example to illustrate its usage:

javascript

import { performance } from "node:perf_hooks"; console.log(performance.now());

Running this code produces output such as:

shell

26.664009988307953

This means that the console.log statement runs about 26 milliseconds from theinitialization of the Node.js process.

Whenever you come across terms like "high resolution" or "high precisiontimestamp" in JavaScript, this refers to values generated by the performance.now()method.

3. Performance Timeline

The Performance Timeline in Node.js is a structured sequence of timing detailsand key performance milestones. These are captured both from the Node.js processitself and any code executed within your application.

This timeline consists of PerformanceEntry objects (and subclasses), eachoffering insights into the type and name of an event, along with precisetimestamps indicating both the start and the duration of the event.

Here's an example of such entries:

javascript

[ PerformanceMark { name: 'query_start', entryType: 'mark', startTime: 49.083899974823, duration: 0, detail: null }, PerformanceMark { name: 'query_end', entryType: 'mark', startTime: 674.0229699611664, duration: 0, detail: null }]

The Performance Timeline is mainly used to monitorand extract comprehensive performance metrics throughout the entire lifecycle ofa Node.js application.

This information is invaluable for real-time performance analysis and can beseamlessly integrated with monitoring systems likeAppSignal for Node.js to enhance application performanceinsights and diagnostics.

Inside the Node.js Performance API

Node.js offers a suite of Performance Measurement APIs within its perf_hooksmodule that are specifically designed to record Node.js performance data.

These APIs are inspired by, and partially implement, theWeb Performance APIsfound in browser environments. However, they are tailored and adapted to suitserver-side programming contexts.

In the following sections, we'll dive into some of the key APIs provided by thismodule:

  1. PerformanceNodeTiming
  2. Performance.now()
  3. Performance.mark()
  4. Performance.getEntries()
  5. Performance.measure()
  6. Performance.clearMarks()
  7. Performance.clearMeasures()
  8. PerformanceResourceTiming

1. PerformanceNodeTiming

In any Node.js program, the initial entry in the Performance Timeline is aPerformanceNodeTiming instance. It distinctively captures the timestamps ofsignificant milestones during the startup phase of a process. To access thisdata, you can print the performance object, as demonstrated below:

javascript

import { performance } from "node:perf_hooks"; console.log(performance);

This results in an output like:

javascript

Performance { nodeTiming: PerformanceNodeTiming { name: 'node', entryType: 'node', startTime: 0, duration: 17.71333795785904, nodeStart: 0.256866991519928, v8Start: 2.246299982070923, bootstrapComplete: 9.73558497428894, environment: 6.018610000610352, loopStart: 13.11082899570465, loopExit: -1, idleTime: 0.03074 }, timeOrigin: 1700776448830.537}

The nodeTiming object, as part of theNode.js runtime timings,provides a detailed view of various stages in the process lifecycle. Here's abreakdown of its key properties:

  • name: Identifies the performance entry, which is the Node.jsprocess in this case.
  • entryType: Specifies the type of performance entry.
  • startTime: Indicates when the measurement started, with 0 denoting thebeginning of the process execution.
  • duration: Represents the duration from the start of the process to the pointwhen the entry was recorded.
  • nodeStart: A high resolution timestamp marking the start of the Node.jsruntime initialization.
  • v8Start: The time at which the V8 JavaScript engine began initializing.
  • bootstrapComplete: The time taken for the Node.js environment to completesetup and get ready to execute user scripts.
  • environment: The duration required to establish the Node.js environment.
  • loopStart: The high resolution timestamp marking the start of the eventloop.
  • loopExit: Indicates when the event loop exited; a value of -1 suggests itwas still active at the time of recording.
  • idleTime: The amount of time the event loop spent idle, not engaged inprocessing tasks.

2. Performance.now()

To measure anoperation's execution time in Node.js, you can use performance.now() to generate high-resolutiontimestamps.

By capturing two timestamps — one before the operation starts and another afterits completion — and then calculating the difference between them, you candetermine an operation's duration.

The following example demonstrates this:

javascript

import { performance } from "node:perf_hooks"; const t0 = performance.now();await fetch("https://jsonplaceholder.typicode.com/todos/1");const t1 = performance.now(); console.log(`Fetch request took ${t1 - t0} milliseconds.`);

Running this script typically results in an output like:

shell

Fetch request took 682.8348079919815 milliseconds.

While this works for simple cases, there are more flexible methods available,which we'll explore later in this tutorial.

3. Performance.mark()

The performance.mark() function is a powerful method for creating and addingnamed markers to the Performance Timeline. These markers can later be retrievedfor performance analysis.

For instance, to track the start and end of an HTTP request, you might use it asfollows:

javascript

import { performance } from "node:perf_hooks"; const mark1 = performance.mark("mark_fetch_start");await fetch("https://jsonplaceholder.typicode.com/todos/1");const mark2 = performance.mark("mark_fetch_end"); console.log(mark1);console.log(mark2);

This will result in an output similar to:

javascript

PerformanceMark { name: 'mark_fetch_start', entryType: 'mark', startTime: 17.95012092590332, duration: 0, detail: null}PerformanceMark { name: 'mark_fetch_end', entryType: 'mark', startTime: 959.4822289943695, duration: 0, detail: null}

In this example, the startTime for each PerformanceMark object reflects ahigh-resolution timestamp, akin to what performance.now() provides. Theduration for such objects is always zero since they represent specific momentsin time.

You can also enrich these markers with additional information using the detailproperty:

javascript

import { performance } from "node:perf_hooks"; const url = "https://jsonplaceholder.typicode.com/todos/1";const options = { detail: { url, },}; const mark1 = performance.mark("mark_fetch_start", options);await fetch(url);const mark2 = performance.mark("mark_fetch_end", options); console.log(mark1);console.log(mark2);

Resulting in:

javascript

// outputs:PerformanceMark { name: 'mark_fetch_start', entryType: 'mark', startTime: 25.053369998931885, duration: 0, detail: { url: 'https://jsonplaceholder.typicode.com/todos/1' }}PerformanceMark { name: 'mark_fetch_end', entryType: 'mark', startTime: 690.2271919250488, duration: 0, detail: { url: 'https://jsonplaceholder.typicode.com/todos/1' }}

By adding the detail property, the performance marks provide not just timinginformation but also contextual data, enhancing the comprehensiveness of yourperformance analysis.

4. Performance.getEntries()

A PerformanceEntry is a unique entity representing a single performance metricwithin an application's Performance Timeline. For instance, thePerformanceMark objects we discussed earlier are subclasses ofPerformanceEntry, characterized by an entryType of mark.

Use getEntries() to retrieve an arrayof all the PerformanceEntry objects logged up to a specific moment inyour program's execution. Here's an example:

javascript

import { performance } from "node:perf_hooks"; performance.mark("mark_fetch_start");await fetch("https://jsonplaceholder.typicode.com/todos/1");performance.mark("mark_fetch_end"); console.log(performance.getEntries());

Running this snippet of code produces an array output like this:

javascript

[ PerformanceMark { name: 'mark_fetch_start', entryType: 'mark', startTime: 49.083899974823, duration: 0, detail: null }, PerformanceMark { name: 'mark_fetch_end', entryType: 'mark', startTime: 674.0229699611664, duration: 0, detail: null }]

For situations where your Performance Timeline contains numerous entries andyou wish to access only specific subsets, Node.js offers getEntriesByName()and getEntriesByType() methods. These methods allow for filtering based on thename and entryType properties of the performance entries:

javascript

// get all entries whose name is `mark_fetch_start`console.log(performance.getEntriesByName("mark_fetch_start")); // get all entries whose name is `mark_fetch_start` and whose type is `mark`console.log(performance.getEntriesByName("mark_fetch_start", "mark")); // get all entries whose entryType is `mark`console.log(performance.getEntriesByType("mark"));

These methods provide a more focused approach to examining performance data,enabling you to isolate and analyze specific aspects of your application'sperformance.

5. Performance.measure()

The Performance.measure() method creates PerformanceMeasure objects thatquantify the duration between two specific points in time (often markedby PerformanceMark objects) within an application's Performance Timeline:

javascript

performance.measure(name[, startMarkOrOptions[, endMark]])

If only the name parameter is supplied, it will generate aPerformanceMeasure object capturing the program's duration up until the call:

javascript

console.log(performance.measure("measureProgram"));

This command results in an output like:

javascript

PerformanceMeasure { name: 'measureProgram', entryType: 'measure', startTime: 0, duration: 936.0637300014496}

A more practical usage of measure() is calculating the elapsed time betweentwo previously recorded PerformanceMark objects:

javascript

import { performance } from "node:perf_hooks"; const url = "https://jsonplaceholder.typicode.com/todos/1";const mark1 = performance.mark("mark_fetch_start");await fetch(url);const mark2 = performance.mark("mark_fetch_end"); console.log( performance.measure("measureProgram", "mark_fetch_start", "mark_fetch_end"));

This will output something similar to the following:

javascript

PerformanceMeasure { name: 'measureFetch', entryType: 'measure', startTime: 22.075212001800537, duration: 903.0410770177841}

In this scenario, startTime corresponds to the start time of the first mark(mark_fetch_start), and duration is the difference in time between the twomarks.

This effectively measures the time that the HTTP request takes, offering aprecise and practical way to assess specific durations within your application'sperformance timeline.

6. Performance.clearMarks()

The performance.clearMarks() function removes PerformanceMarkobjects from the Performance Timeline. This feature provides flexibility,allowing you to either clear all existing marks or remove specific onesidentified by a name.

This is particularly useful for managing and resetting performance data,especially in long-running applications or during repeated testing phases.

The function can be employed as follows:

javascript

// Remove all `PerformanceMark` objectsperformance.clearMarks(); // Remove only `PerformanceMark` objects named `mark_fetch_start`performance.clearMarks("mark_fetch_start");

7. Performance.clearMeasures()

This function does the same thing as clearMarks() but removesPerformanceMeasure objects instead.

8. PerformanceResourceTiming

The PerformanceResourceTiming API is a specialized tool for capturingdetailed network timing data, allowing you to track the duration of networkrequests in your code.

While we've used methods like performance.now(),performance.mark(), and performance.measure() to track the duration of anHTTP request, they are more general-purpose tools.

In practice, the fetch API automatically gathers performance timings for eachrequest, which are then recorded in the Performance Timeline asPerformanceResourceTiming objects.

javascript

import { performance } from "node:perf_hooks"; const url = "https://jsonplaceholder.typicode.com/posts/1";const response = await fetch(url);await response.json();console.log(performance.getEntries());

Executing this script will result in an output resembling:

javascript

[ PerformanceResourceTiming { name: 'https://jsonplaceholder.typicode.com/posts/1', entryType: 'resource', startTime: 33.411154985427856, duration: 1665.9909150600433, initiatorType: 'fetch', nextHopProtocol: undefined, workerStart: 0, redirectStart: 0, redirectEnd: 0, fetchStart: 33.411154985427856, domainLookupStart: undefined, domainLookupEnd: undefined, connectStart: undefined, connectEnd: undefined, secureConnectionStart: undefined, requestStart: 0, responseStart: 0, responseEnd: 1699.4020700454712, transferSize: 300, encodedBodySize: 0, decodedBodySize: 0 }]

This PerformanceResourceTiming object encapsulatesseveral measurementsfor the HTTP request. Key attributes include:

  • startTime, fetchStart: The high resolution timestamp marking thecommencement of the resource fetch.
  • responseEnd: The high resolution timestamp right after Node.js receives thelast byte of the resource (or just before the transport connection closes,whichever occurs first).
  • duration: The difference between responseEnd and startTime.
  • transferSize: The total size of the fetched resource, including bothresponse headers and body, measured in octets (commonly the same as bytes).

It's important to note that this data gets recorded in the timeline only whenthe response is actually used. Omitting the await response.json() line, forinstance, would result in an empty array.

Finally, let's take a quick look at how to manage resource buffer sizes.

Managing Resource Buffer Sizes in Node

The Performance Timeline has a default capacity limit forPerformanceResourceTiming objects, set at 250. To adjust this limit,you can utilize the setResourceTimingBufferSize() method:

javascript

performance.setResourceTimingBufferSize(500);

This command increases the buffer size, allowing up to 500PerformanceResourceTiming objects to be stored simultaneously in thePerformance Timeline.

If you need to clear all the existing PerformanceResourceTiming objects fromthe timeline, the clearResourceTimings() method comes in handy:

javascript

performance.clearResourceTimings();

You can also listen for the resourcetimingbufferfull event to take actionswhen the performance resource timing buffer is full. For example, you couldincrease the buffer capacity or clear the buffer so that new entries can beadded:

javascript

performance.addEventListener("resourcetimingbufferfull", (event) => { if (performance.getEntriesByType("resource").length < 1000) { performance.setResourceTimingBufferSize(1000); } else { performance.clearResourceTimings(); }});

And that's it for now!

Up Next: Practical Uses of Node.js Performance APIs

In this blog post, we focused on examining the most important Node.jsPerformance APIs and their various uses.

In the next and final part of this series, we'll dive into practical implementationsof these APIs. I'll demonstrate their real-world value to optimize and resolve performance issues in your Node.js applications.

Stay tuned, and happy coding!

P.S. If you liked this post, subscribe to our JavaScript Sorcery list for a monthly deep dive into more magical JavaScript tips and tricks.

P.P.S. If you need an APM for your Node.js app, go and check out the AppSignal APM for Node.js.

Node.js Performance APIs: An Introduction | AppSignal Blog (2024)
Top Articles
How do I get money out of my PayPal account?
TLS vs SSL vs HTTPS: What’s the Difference? - Comodo SSL Resources
Katie Pavlich Bikini Photos
Gamevault Agent
Hocus Pocus Showtimes Near Harkins Theatres Yuma Palms 14
Free Atm For Emerald Card Near Me
Craigslist Mexico Cancun
Hendersonville (Tennessee) – Travel guide at Wikivoyage
Doby's Funeral Home Obituaries
Vardis Olive Garden (Georgioupolis, Kreta) ✈️ inkl. Flug buchen
Select Truck Greensboro
How To Cut Eelgrass Grounded
Pac Man Deviantart
Alexander Funeral Home Gallatin Obituaries
Craigslist In Flagstaff
Shasta County Most Wanted 2022
Energy Healing Conference Utah
Testberichte zu E-Bikes & Fahrrädern von PROPHETE.
Aaa Saugus Ma Appointment
Geometry Review Quiz 5 Answer Key
Walgreens Alma School And Dynamite
Bible Gateway passage: Revelation 3 - New Living Translation
Yisd Home Access Center
Home
Shadbase Get Out Of Jail
Gina Wilson Angle Addition Postulate
Celina Powell Lil Meech Video: A Controversial Encounter Shakes Social Media - Video Reddit Trend
Walmart Pharmacy Near Me Open
Dmv In Anoka
A Christmas Horse - Alison Senxation
Ou Football Brainiacs
Access a Shared Resource | Computing for Arts + Sciences
Pixel Combat Unblocked
Umn Biology
Cvs Sport Physicals
Mercedes W204 Belt Diagram
Rogold Extension
'Conan Exiles' 3.0 Guide: How To Unlock Spells And Sorcery
Teenbeautyfitness
Weekly Math Review Q4 3
Facebook Marketplace Marrero La
Nobodyhome.tv Reddit
Topos De Bolos Engraçados
Gregory (Five Nights at Freddy's)
Grand Valley State University Library Hours
Holzer Athena Portal
Hampton In And Suites Near Me
Stoughton Commuter Rail Schedule
Bedbathandbeyond Flemington Nj
Free Carnival-themed Google Slides & PowerPoint templates
Otter Bustr
Selly Medaline
Latest Posts
Article information

Author: Kimberely Baumbach CPA

Last Updated:

Views: 6329

Rating: 4 / 5 (61 voted)

Reviews: 84% of readers found this page helpful

Author information

Name: Kimberely Baumbach CPA

Birthday: 1996-01-14

Address: 8381 Boyce Course, Imeldachester, ND 74681

Phone: +3571286597580

Job: Product Banking Analyst

Hobby: Cosplaying, Inline skating, Amateur radio, Baton twirling, Mountaineering, Flying, Archery

Introduction: My name is Kimberely Baumbach CPA, I am a gorgeous, bright, charming, encouraging, zealous, lively, good person who loves writing and wants to share my knowledge and understanding with you.