The 5 most transformative JavaScript features from ES11

Last updated on September 25, 2024
The 5 most transformative JavaScript features from ES11

JavaScript has come a long way in the past 10 years with brand new feature upgrades in each one.

Let’s take a look at the 5 most significant features that arrived in ES11; and see the ones you missed.

1. Modularization on the fly: Dynamic imports

ES11 was the awesome year when import could now act as function, like require().

An async function.

Keeping imports at the top level was no longer a must; We could now easily resolve the module's name at compile time.

Loading modules optionally and only when needed for high-flying performance...

async function asyncFunc() {
  if (condition) {
    const giganticModule = await import('./gigantic-module');
  }
}

Loading modules based on user or variable input...

import minimist from 'minimist';

const argv = minimist(process.argv.slice(2));

viewModule(argv.name);

async function viewModule(name) {
  const module = await import(name);
  console.log(Object.keys(module));
}

It's also great for using ES modules that no longer support require():

// ❌ require() of ES modules is not supported
const chalk = require('chalk');
console.log(chalk.blue('Coding Beauty'));

(async () => {
  // ✅ Runs successfully
  const chalk = (await import('chalk')).default;
  console.log(chalk.blue('Coding Beauty'));
})();

2. Promise.allSettled()

But we already had Promise.all() to wait for all the Promises in a list to resolve?

const responses = await Promise.all([
  fetch(endpoint1),
  fetch(endpoint2),
]);

So what was the point of this, right?

But no, allSettled() turns out to be quite different from all().

Promise.all(): If even a single Promise in the list fails, everything fails.

But you see the problem: We'd have no idea if one failed and which succeeded.

What if you want to retry the failed errors until they do succeed? You're stuck.

Until you turn to Promise.allSettled():

❌ Before ES11:

// ❌ Promise.all()
async function fetchData() {
  const apiUrl = 'api.tariibaba.com';
  const endpoint1 = `${apiUrl}/route1`;
  const endpoint2 = `${apiUrl}/route2`;

  try {
    const responses = await Promise.all([
      fetch(endpoint1),
      fetch(endpoint2),
    ]);
  } catch (err) {
    // ❌ Which failed & which succeeded? We have no idea
    console.log(`error: ${err}`);
  }
  // ...
}

✅ After ES11:

Promise.allSettled(): Wait for every Promise to fail or resolve.

// ✅ Promise.allSettled()
async function fetchData() {
  const apiUrl = 'api.tariibaba.com';

  const endpoint1 = `${apiUrl}/route1`;
  const endpoint2 = `${apiUrl}/route2`;

  try {
    const promises = await Promise.allSettled([
      fetch(endpoint1),
      fetch(endpoint2),
    ]);
    const succeeded = promises.filter(
      (promise) => promise.status === 'fulfilled'
    );
    const failed = promises.filter(
      (promise) => promise.status === 'rejected'
    );
    // ✅ now retry failed API requests until succeeded?
  } catch (err) {
    // We don't need this anymore!
    console.log(`error: ${err}`);
  }
  // ...
}

3. Optional chaining

?. is all over the place now but it all started from ES11.

We've been checking vars for null since the dawn of time but it gets pretty cumbersome when we're null-checking nested properties.

❌ Before ES11:

const a = {
  b: {
    c: {
      d: {
        site: 'codingbeautydev.com',
        name: null,
      },
    },
  },
};

// ❌ Must check every property for null
if (a && a.b && a.b.c && a.b.c && a.b.c.d.site) {
  console.log(a.b.c.d.site);
}

✅ After ES11:

With the optional chaining operator:

// `?.` auto-checks every property for null

// if any prop in the chain is null, short-circuit
// and return null
if (a?.b?.c?.d?.site) {
  console.log(a.b.c.d.site);
}

4. Nullish coalescing

?? was one of the most impactful JavaScript additions.

A powerful to set a variable to a default value and use it at the same time.

❌ Before ES11:

We repeat the variable unnecessarily:

console.log(str1 ? str1 : 'codingbeautydev.com'); // coding is cool

console.log(str2 ? str2 : 'codingbeautydev.com'); // codingbeautydev.com

✅ After ES12:

?? keeps things clean and readable:

const str1 = 'coding is cool';

const str2 = null;

console.log(str1 ?? 'codingbeautydev.com'); // coding is cool

console.log(str2 ?? 'codingbeautydev.com'); // codingbeautydev.com

It coalesces.

Left and right combine to form a non-null whole:

5. Go big or go home: Big Ints

The name BigInt gives it away: loading up on humongous integer values:

const bigInt =
  240389470239846028947208942742089724204872042n;

const bigInt2 = BigInt(
  '34028974029641089471947861048917649816048962'
);

console.log(typeof bigInt);
console.log(bigInt);

console.log(typeof bigInt2);
console.log(bigInt2);

console.log(bigInt * bigInt2);

Because normal integers can't:

// ✖️ Stored as double
const normalInt = 240389470239846028947208942742089724204872042;

const normalInt2 = 34028974029641089471947861048917649816048962;

console.log(typeof normalInt);
console.log(normalInt);

console.log(typeof normalInt2);
console.log(normalInt2);

// ✖️ Precision lost
console.log(normalInt * normalInt2);

Final thoughts

These are the juicy new JavaScript features that arrived in the ES12.

Use them to boost your productivity as a developer and write cleaner code with greater conciseness, expressiveness and clarity.

Coding Beauty Assistant logo

Try Coding Beauty AI Assistant for VS Code

Meet the new intelligent assistant: tailored to optimize your work efficiency with lightning-fast code completions, intuitive AI chat + web search, reliable human expert help, and more.

See also