At New Relic, we believe that Application Performance Monitoring (APM) should be available for the latest and greatest technology platforms. And we have long been committed to supporting the Node.js ecosystem and providing our customers with timely support for the newest versions of Node.js.

That’s why we are so pleased to announce the release of Version 2.3.0 of the New Relic Node.js agent. With this release, our support for the async/await keywords with Node 8 moves out from behind its feature flag and is now enabled by default.

Published under the codename Carbon, Node 8 was originally slated for release by Nodejs.org in late April but was delayed to allow Node to integrate a version of Google’s V8 JavaScript engine that includes Ignition and TurboFan, the new JavaScript execution pipeline. We shipped our initial support for Node 8 shortly after its release at the end of May and have now updated the agent to include support for the use of Async/Await.

Node 8 is packed with features

Node.js 8.0.0 ships with JavaScript Engine V8 5.8, an update to the JavaScript runtime that includes major improvements in performance and developer-facing APIs. There is also plenty to be excited about with Node 8 itself.

Introducing N-API: One of the most significant new features is the new N-API module, which aims to provide a stable ABI (Application Binary Interface) across all future versions of Node.js. This new API is intended to insulate Addons from changes in the underlying JavaScript engine and allow native modules compiled for one version to run on later versions of Node.js without being recompiled.

Support for async/await: Another key addition is the introduction of the async and await keywords. While Node 7.6.0 was the first version to support async functions without a feature flag, Node 8 is the first LTS version to support it. Being an LTS release, it was quickly adopted by the community. In combination with the new await keyword, this makes using Promises even cleaner and easier to read.

Promises already represented a huge step forward in getting out of “callback hell.” Compare these two examples, both of which perform the same sequence of steps. Using the traditional callback style, we might write something like this:

function callbackStyle(cb) {
  doSomething((err, something) => {
    if (err) {
      cleanupSomething()
      return cb(err)
    }

    doSomethingMore(something, (err, more) => {
      if (err) {
        cleanupMore()
        return cb(err)
      }

      doFinalSomething(more, (err, final) => {
        if (err) {
          cleanupFinal()
          return cb(err)
        }

        cb(final)
      })
    })
  })
}

function promiseStyle() {
  return doSomething()
    .then((something) => doSomethingMore(something))
    .then((more) => doSomethingFinal(more))
    .catch((err) => {
      cleanupEverything()
      throw err
    })
}

With the new async functions built on top of Promises, this asynchronous code example can be rewritten to read just as cleanly as synchronous code, as shown here:

async function awaitStyle() {
  try {
    const something = await doSomething()
    const more = await doSomethingMore(something)
    return await doSomethingFinal(more)
  } catch (err) {
    cleanupEverything()
    throw err
  }
}

That alone would be worth the price of admission. But wait, there’s more! Not only does the new async function support clean up of simple procedural code, it also simplifies asynchronous loops:

async function awaitMapSeries(items, asyncModifier) {
  const out = new Array(items.length)
  for (let i = 0; i < items.length; ++i) {
    out[i] = await asyncModifier(items[i], i, items)
  }
  return out
}

async function awaitMapParallel(items, asyncModifier) {
  return await Promise.all(items.map(asyncModifier))
}

Awesome, right?

Async Hooks API enables monitoring across Node’s asynchronous operations

Last but not least is Async Hooks, which enables users to monitor and track the state across Node’s asynchronous operations, laying the groundwork for better diagnostic tools in the future. Async Hooks support was added late in the Node 8 development cycle, which was a key factor in our decision to ship New Relic’s initial support for Node 8 without support for async/await. We wanted to leverage Async Hooks to implement our instrumentation support for async/await, but needed additional time to monitor its maturation and to adequately test and validate a solution built on it.

code snippet using await

Example showing an async middleware retrieving data from MongoDB with the new “await” syntax.

transaction trace in new relic

Corresponding transaction trace showing time spent awaiting the result of these datastore operations.

 

The new improvements and feature releases certainly create the most seamless workflow ever for Node.js developers, likely resulting in significant performance enhancements. For more information on New Relic’s Async/Await support, see the New Relic Node.js documentation.

 

Shreyans Parekh is a Product Marketing Manager at New Relic, where his job is to focus on market and industry dynamics in the areas of cloud migration and DevOps. His writing has appeared in publications by Internet Retailer, Intuit, Apttus and IBM Bluewolf. He can be reached on Twitter @ShreyParekh. View posts by .

Interested in writing for New Relic Blog? Send us a pitch!