Monitoring platform for keeping systems up and running at all times.
Full stack visibility across the entire stack.
Detect and resolve any incident in record time.
Conform to industry best practices.
It’s the end of AWS Lambda support for Node.js v10. AWS Lambda support for Node.js 10 is due to end in August 2021. It’s time to switch! In this article, we’re discussing and comparing the differences of working with Node.js 10 and Node.js 14 + AWS Lambda, the impacts, and benefits of this change.
AWS Lambda supports multiple versions of programming language runtimes, but not forever. That’s because the creators of these programming languages don’t support them infinitely either.
AWS Lambda also only supports the long-term support (LTS) versions of Node.js: the even version numbers. Currently, versions 10, 12, and 14 are all supported, but in August 2021, the support for version 10 is running out.
So it’s time to switch, but besides evading the support end, what benefits does it bring to switch directly to version 14? In this article, I will go over the changes that have happened since version 10 of Node.js.
Let’s start with the ECMAScript additions to JavaScript. Usually, they are supported in the JavaScript engine before they are standardized. The idea is that nothing, that isn’t working in practice, gets standardized.
This doesn’t mean that all JavaScript engines support every ECMAScript feature before it is standardized. After all, the committee can’t wait for every JavaScript engine that is out there. For example, proper tail call optimization is standardized for years now, but only a few engines have implemented the feature.
Anyway, let’s check what happened since version 10!
This is one of the biggest additions, in my opinion. Gone are the crashes because you tried to access an attribute of an undefined variable, or you set a default for a value that was null-ish.
The optional chaining operator ?. is an alternative to the regular chaining operator . they can be used all the same; the only difference is that the regular chaining operator will crash if you try to access an attribute on an undefined variable. The optional chaining operator will simply return undefined.
?.
.
undefined
const deepValue = path?.to?.notDefined?.deep?.value;
If at least one part of this chain isn’t an object, deepValue will be set to undefined.
deepValue
The nullish coalescing operator ?? is an alternative to the logical or operator || used to set variables to a default value.
??
||
The problem with the logical or operator was that it also used the default when the value was something that could be automatically converted to false, like the number 0. The nullish coalescing operator would only use the default when the checked variable was null or undefined.
false
0
<p>const input = 0;</p> <p>let amount;</p> <p>amount = input || 20;</p> <p>amount = input ?? 20;</p>
In the example, the logic or operator would set the amount to 20 even if the input was 0, but the coalescing operator would leave it at 0.
20
input
The two new operators work nicely in tandem.
const deepValue = notDefined?.deep?.value ?? "default text";
The Symbol class got two new additions. If you create a new symbol with a description, you can now check it later with the description property.
This example will log “description” to the console.
description
const sym = Symbol("description"); console.log(sym.description);
There is also a new well-known symbol called matchAll. It can be used to create custom matchAll functions for your data types.
matchAll
const numbers = { *[Symbol.matchAll] (str) { for (const n of str.matchAll(/[0-9]+/g)) yield n[0]; } }; console.log(Array.from("2021-05-12".matchAll(numbers)));
The object numbers needs a generator function (that’s what the * means) in its Symbol.matchAll property, so it can be used as a parameter for the String.prototype.matchAll method. This example will output ["2021", "05", "12"].
numbers
*
Symbol.matchAll
String.prototype.matchAll
["2021", "05", "12"]
The unification of window, self, frames, and global into one global object called globalThis. Back in the days, the access to the global object differed from where your script was running, but if you tried to access window inside Node.js or a worker thread, it would fail. With globalThis your script doesn’t have to care anymore.
window
self
frames
global
globalThis
This example works in all current browser versions and Node.js:
globalThis.aGlobalVariable = 123;
Since Node.js 10, there have been some additions to classes as well: instance class fields, static class fields, and private class fields.
Before version 12, instance fields had to be set in the constructor, and static fields had to be set via the prototype, and both were always public. Now you can set them all in the class definition and modify their visibility.
Let’s see how it works in practice:
class ResourceManager { static publicStaticField = 123; static #privateStaticField = 456; static publicStaticMethod() {} static #privateStaticMethod() {} publicInstanceField = 123; #privateInstanceField = 456; publicMethod() {} #privateMethod() {} }
If you end up with a nested array, and you want to lift the nested elements back to the top array, the new flat method for arrays is the solution.
flat
const nested = [1, 2, 3, [4, 5], 6, 7]; const flattened = nested.flat();
The example above, flattened, will contain [1, 2, 3, 4, 5, 6, 7]. But keep in mind that it only flattens a depth of one; you have to call it again if you have deeper nested arrays you want to get rid of.
[1, 2, 3, 4, 5, 6, 7]
Since the flat method is usually called to clear up the array structure before a call to the map method, a shortcut method called flatMap() will work as a map with a flat applied before.
map
In the following example, the item is always a number and never an array because the nested array is flattened before passed to the callback function.
const nestedNumbers = [1, 2, [3, 4], 5]; const squaredNumbers = nested.flatMap(item => item * item);
The new Intl.DisplayNames API allows to translate region, language, and script display names automatically.
This would display “德文”, the traditional Chinese translation of the language “German”.
const tradChinese = new Intl.DisplayNames( ['zh-Hant'], {type: 'language'} ); tradChinese.of('de');
It’s now possible to add underlines to number literals to make them more readable inside the code.
const oneMillion = 1_000_000; const hexBlue = 0x00_00_FF;
Since version 10, many performance improvements have happened. The startup time improved by 30%, which can shave quite some time from your cold start latency.
The heap size configuration was done with two default values before, but in version 14, Node.js will take the actual available memory into account when configuring the optimal heap size. Since AWS Lambda allows for very flexible memory configurations per function, this could help you get more bang for the buck.
Find out more about saving money on Lambdas in our 6 AWS Lambda Cost Optimization Strategies That Work article.
I tried a prime number calculation on AWS Lambda with Node.js 10 and 14 to see the differences. First, I calculated primes between one hundred and one thousand and then those between one hundred and one billion. I run this with 128MB and 1024MB memory configuration, to see how the init times and runtime durations changed between the two versions.
The following graphs illustrate the differences.
Blue marks Node.js 10 and red 14. As you can see, the init timings got better by ~20% and I just switched the runtime version. Because Lambda functions are billed by millisecond this is real money you can save. Also, short-running Lambda functions can reduce the latency quite a bit.
Again, blue marks Node.js 10 and red 14. This time I measured the duration an invocation took. The difference between the primes between hundred and thousand wasn’t much, so I left them out here, but for longer computations, like finding the primes between one hundred and one billion, it makes a huge difference. This saves a huge chunk of money and could even make it possible to do slow calculations synchronously as an API Gateway response now.
The diagnostic reports help with analyzing the behavior of a Node.js program. It will log out a JSON formatted string into a file that you can check for more details than CloudWatch gives you.
Find out how you can get even more detailed and faster AWS data analytics, observability and debugging.
TLS 1.3 and QUIC protocol support have landed in the LTS version of Node.js, so your Lambda can keep communicating with the latest services out there.
The worker threads API is now stable. You can use it for computation-intensive workloads. Usually, Node.js is a single-threaded environment, but you can now execute JavaScript with worker threads in parallel. When you configure Lambda memory, the vCPU cores are also configured implicitly. If you set a memory limit of 10 GB, you also get 6 vCPU cores, which you can now utilize with Node.js worker threads.
Full International Components for Unicode (ICU) support has landed in Node.js. ICU is a set of “libraries providing Unicode and Globalization support for software applications”. The full list of features can be found on Node.js’s GitHub Repository.
The sun is setting on the LTS for Node.js version 10 in a few months’ time, and so is the AWS Lambda runtime support. If you have to switch anyway, why not go straight to version 14? It will give you a longer support time in the future, and you get a whole bag of extra features that improve the coding of Lambda functions and their performance on the AWS platform.
Further reading:
AWS Lambda Node.js errors and exceptions
How to deploy a Node.js application to AWS Lambda using Serverless
AWS Lambda metrics you should definitely monitoring
In this guide, we’ll talk about common problems developers face with serverless applications on AWS and share some practical strategies to help you monitor and manage your applications more effectively.
Today we are announcing a new, updated pricing model and the end of free tier for Dashbird.
In this article, we’re covering 4 tips for AWS Lambda optimization for production. Covering error handling, memory provisioning, monitoring, performance, and more.
Dashbird was born out of our own need for an enhanced serverless debugging and monitoring tool, and we take pride in being developers.
Dashbird gives us a simple and easy to use tool to have peace of mind and know that all of our Serverless functions are running correctly. We are instantly aware now if there’s a problem. We love the fact that we have enough information in the Slack notification itself to take appropriate action immediately and know exactly where the issue occurred.
Thanks to Dashbird the time to discover the occurrence of an issue reduced from 2-4 hours to a matter of seconds or minutes. It also means that hundreds of dollars are saved every month.
Great onboarding: it takes just a couple of minutes to connect an AWS account to an organization in Dashbird. The UI is clean and gives a good overview of what is happening with the Lambdas and API Gateways in the account.
I mean, it is just extremely time-saving. It’s so efficient! I don’t think it’s an exaggeration or dramatic to say that Dashbird has been a lifesaver for us.
Dashbird provides an easier interface to monitor and debug problems with our Lambdas. Relevant logs are simple to find and view. Dashbird’s support has been good, and they take product suggestions with grace.
Great UI. Easy to navigate through CloudWatch logs. Simple setup.
Dashbird helped us refine the size of our Lambdas, resulting in significantly reduced costs. We have Dashbird alert us in seconds via email when any of our functions behaves abnormally. Their app immediately makes the cause and severity of errors obvious.