My favorite features coming in Javascript ES2021

Photo by KiVEN Zhao on Unsplash
It’s incredible to think that the LANDMARK Javascript release es6 was over 6 years ago (See the official release here)! Javascript and its community have learned a lot since that time. One point of criticism was how HUGE the es6 release was and how difficult it was to learn EVERYTHING. With that said, ES2021 adds a nice digestible set of awesome features coming to your browser soon :) Here are my favorite things being added!

1. String.prototype.replaceAll()

const whitespace = "This is a sentence with whitespaces";

// The old way in javascript using replace - Only replaces first occurence
const oldWay = whitespace.replace(" ",""); // "thisis a sentence with whitespaces"

// So you have to make sure you are explicit about replace globally with a Regex!
const oldWayGlobalRegex = whitespace.replace(/ /g, ""); // "thisisasentencewithwhitespaces"

// Now we have a much cleaner syntax for doing a replace
const awesomeWay = whitespace.replaceAll(" ", ""); // "thisisasentencewithwhitespaces"

I think this is a really slick feature. Hopefully you think the same. Have you ever had to replace some characters in javascript with String.prototype.replace() only to find you had to have a global flag with a regex? Well not anymore, because now with String.prototype.replaceAll(), it’s very straightforward and much more readable.

Let’s go see its MDN entry:

The String.prototype.replaceAll() method returns a new string with all matches of a pattern replaced by a replacement. The pattern can be a string or a RegExp, and the replacement can be a string or a function to be called for each match.

Check it out on the MDN

2. Numeric separators

// What's easier to read? With numeric separators things get A LOT easier!
var oneMillion = 1000000;
var oneMillion = 1_000_000;

var oneBillion = 1000000000;
var oneBillion = 1_000_000_000;

var hexBytes = 0xFFECDE5E
var hexBytes = 0xFF_EC_DE_5E

Maybe I think this is cooler than it really is but I think this feature speaks for itself. I used to make a few Javascript games here and there and I feel this would have really helped me back then with some of the values I stored. I do feel though that the hex stuff I will start using today. Overall it’s SOOO much easier to read, I love it.

View the TC39 Proposal

3. Logical OR assignment operators

// The logical OR assignment (x ||= y) operator only assigns if x is false.

// Imagine we provide a default description for a user. 
function getUser() {
    const user = someApiCallThatReturnsUserObject();
    user.description ||= "No description provided";
    return user;

// You can use it for default arguments
function sayHello (message) {
    message ||= "My Default message"; 

// Taking from the tc39 proposal check out this nice code snippet. Is it easier to read?
document.getElementById('previewZone').innerHTML ||= '<i>Nothing to preview</i>';

// These are a little verbose, good candidates for logical or assignment for cleaner code
document.getElementById('previewZone').innerHTML = document.getElementById('previewZone').innerHTML ? document.getElementById('previewZone').innerHTML : '<i>Nothing to preview</i>';

document.getElementById('previewZone').innerHTML = document.getElementById('previewZone').innerHTML || '<i>Nothing to preview</i>';

This is a slick feature and to understand why it’s so cool is to compare it to the other ways of doing this. Granted ES6 brought us default parameters in functions which I feel this would be a good candidate for (MDN here) using it, but this still has a lot of value in general day-to-day usage of Javascript.
Also if you like this feature, check out the logical and operator (MDN here).

Check it out on the MDN

4. Promise.any()

const slowPromise = new Promise((resolve) => setTimeout(resolve, 100, 'quick'));
const fastPromise = new Promise((resolve) => setTimeout(resolve, 500, 'slow'));
const deadPromise = new Promise.reject("I failed loading")

const promises = [slowPromise, fastPromise, deadPromise];

Promise.any(promises).then((value) => console.log(value));

// expected output: "quick"


This is an interesting feature for sure. So what’s a good use case for this? Borrowing from the MDN we get a good idea here… > “This method is useful for returning the first promise that fulfills. It short-circuits/stops after a promise fulfills, so it does not wait for the other promises to complete once it finds one. Unlike Promise.all(), which returns an array of fulfillment values, we only get one fulfillment value (assuming at least one promise fulfills. “

What’s a good example of using Promise.any()?

In our weekly SPS UI Guild we actually discussed this new feature. One cool idea that a fellow guild member thought of was … > “…you were trying to get an accurate time from a time server and you were trying many time servers, when the first one came back, you could use any because the rest would be canceled…”

Or Imagine we are hitting an API endpoint and what comes back is relatively large/slow like a large business information analytics sales report for the whole year whose data changes infrequently. We could have a cached API and the live data API BOTH go out and whichever API comes back first is displayed to the user. Cool right?

What’s the difference between Promise.race() and this?

There is a very important KEY difference between the two, basically, Promise.any() vs Promise.race() boils down to how they handle failing Promises.

  • Promise.any() - Brings back the first promise, and only one result. Shows failure when all promises fail.
  • Promise.race() - Brings back the first promise that succeeds or fails.

Check it out on the MDN

And there’s even more in the release…

And there are even more features coming in the release, notably weakrefs (MDN here). Check out the v8 release notes for even more info.

Hopefully, you can start to use these features in your daily workflow, and before you know it we’ll have es2022 features.

Happy coding!

Andy Sciro

Andrew Sciro @andysciro