• Tutorials
  • Modern JavaScript Features - Part 2

    Views176

    In Part 1 we covered the syntactic foundations of modern JavaScript. This second part dives into asynchronous programming and code organization — promises, async/await, and modules — which are essential for building real applications.

    #Promises

    A promise represents a value that may be available now, later, or never. It's the standard way to handle asynchronous operations like network requests.

     1const fetchUser = (id) => {
     2    return new Promise((resolve, reject) => {
     3        setTimeout(() => {
     4            if (id > 0) {
     5                resolve({ id, name: "Ada" });
     6            } else {
     7                reject(new Error("Invalid id"));
     8            }
     9        }, 1000);
    10    });
    11};
    

    Consume a promise with .then(), .catch(), and .finally():

     1fetchUser(1)
     2    .then((user) => console.log(user.name))
     3    .catch((error) => console.error(error.message))
     4    .finally(() => console.log("Done"));
    

    #Chaining

    Each .then() returns a new promise, so you can chain operations sequentially. Returning a value passes it to the next handler; returning a promise waits for it to settle.

     1fetchUser(1)
     2    .then((user) => fetchPosts(user.id))
     3    .then((posts) => console.log(posts.length))
     4    .catch((error) => console.error(error));
    

    #async / await

    async/await is syntactic sugar over promises that lets you write asynchronous code that reads like synchronous code.

     1async function loadUser(id) {
     2    try {
     3        const user = await fetchUser(id);
     4        const posts = await fetchPosts(user.id);
     5        return { user, posts };
     6    } catch (error) {
     7        console.error("Failed to load:", error.message);
     8    }
     9}
    

    An async function always returns a promise, and await pauses execution until the awaited promise settles.

    #Running in Parallel

    Awaiting sequentially when operations are independent wastes time. Use Promise.all to run them concurrently.

     1async function loadDashboard(userId) {
     2    const [profile, settings, notifications] = await Promise.all([
     3        fetchProfile(userId),
     4        fetchSettings(userId),
     5        fetchNotifications(userId),
     6    ]);
     7    return { profile, settings, notifications };
     8}
    

    Related combinators:

    • Promise.all — resolves when all settle, rejects on the first rejection.
    • Promise.allSettled — waits for all and reports each outcome.
    • Promise.race — settles as soon as the first promise settles.
    • Promise.any — resolves with the first fulfilled promise.

    #ES Modules

    ES Modules (ESM) provide a standardized way to split code across files using import and export.

    #Named Exports

     1// math.js
     2export const PI = 3.14159;
     3export function square(n) {
     4    return n * n;
     5}
    
     1// app.js
     2import { PI, square } from "./math.js";
     3console.log(square(PI));
    

    #Default Exports

    A module can have one default export, useful for a single primary value.

     1// logger.js
     2export default function log(message) {
     3    console.log(`[LOG] ${message}`);
     4}
    
     1// app.js
     2import log from "./logger.js";
     3log("Started");
    

    #Renaming and Namespace Imports

     1import { square as sq } from "./math.js";
     2import * as math from "./math.js";
     3
     4console.log(sq(4));
     5console.log(math.PI);
    

    #Dynamic Imports

    You can load modules on demand, returning a promise. This enables code splitting and lazy loading.

     1async function loadChart() {
     2    const { renderChart } = await import("./chart.js");
     3    renderChart();
     4}
    

    #Wrapping Up

    Promises and async/await tame asynchronous flows, while ES Modules keep growing codebases organized and reusable. Together they underpin virtually every modern JavaScript project. In Part 3 we'll explore iterators, generators, and newer additions like optional chaining and nullish coalescing.

    profile image of Petar Vasilev

    Petar Vasilev

    Petar is a web developer at Mitkov Systems GmbH. He is fascinated with the web. Works with Laravel and its ecosystem. Loves learning new stuff. Writes with the help of #ai.

    More posts from Petar Vasilev