JavaScriptESNextAsync/AwaitPatternsModules

Top-Level Await: Removing the Wrapper

F
Frontend Architect
Featured Guide 12 min read

Stop writing (async () => {})().

We've all done it. To use await at the root of a file, we had to wrap everything in an Immediately Invoked Function Expression (IIFE).

Top-Level Await makes modules implicitly async. The module system pauses execution until the promise resolves.

02. Clean Initialization

This is perfect for modules that rely on asynchronous data to initialize their exports.

Old (Export Promise)

// db.js
let db;
export const init = async () => {
  db = await connect();
};
export const getDb = () => db;

// consumer.js
await init(); // 🤢 Must remember to call
getDb().query(...);
                    

New (Export Value)

// db.js
const db = await connect(); 
export default db; // šŸš€ Ready to use!

// consumer.js
import db from './db.js';
// Module waits for connection!
db.query(...); 
                    

03. Double-Edged Sword

Be careful. If efficient parallelization isn't managed, a top-level await can block the importing of other modules.

āš ļø Warning: If db.js takes 10 seconds to connect, your entire app startup pauses for 10 seconds before executing the next line of import in the consumer.

Deep Dive: Parallel Loading

The Javascript module loader is smart. If two modules don't depend on each other, it tries to load them in parallel.

However, if `App` imports `User` which imports `DB`, you are stuck in a serial chain. Top-Level Await effectively pauses the graph construction at that node.

04. The Senior Engineer's Take

Use Sparingly

Top-Level Await is a fantastic tool for Service Initialization (DBs, Wasm loading, Config fetching).

Do NOT use it for heavy computation or slow network requests that aren't critical to app startup.

⚔ Interactive Playground

import React, { useState, useEffect } from 'react';

// ā³ Module Loader Visualizer

export default function AwaitDemo() {
    const [status, setStatus] = useState('idle'); // idle, loading, done
    const [modules, setModules] = useState([
        { id: 'config', name: 'Config.js', duration: 1500, state: 'pending' },
        { id: 'db', name: 'Database.js', duration: 3000, state: 'pending' },
        { id: 'app', name: 'App.js', duration: 500, state: 'pending' }
    ]);
    const [logs, setLogs] = useState([]);

    const startLoading = async () => {
        if (status === 'loading') return;
        setStatus('loading');
        setModules(m => m.map(Mod => ({ ...Mod, state: 'pending' })));
        setLogs([]);

        addLog('Starting Application...');

        // 1. Config (TLA - Top Level Await)
        addLog('Importing Config...');
        setModules(m => m.map(Mod => Mod.id === 'config' ? { ...Mod, state: 'loading' } : Mod));
        await wait(1500); 
        setModules(m => m.map(Mod => Mod.id === 'config' ? { ...Mod, state: 'ready' } : Mod));
        addLog('āœ… Config Ready');

        // 2. DB (TLA - dependent on Config technically, but let's say serial import)
        addLog('Importing Database...');
        setModules(m => m.map(Mod => Mod.id === 'db' ? { ...Mod, state: 'loading' } : Mod));
        await wait(3000); 
        setModules(m => m.map(Mod => Mod.id === 'db' ? { ...Mod, state: 'ready' } : Mod));
        addLog('āœ… Database Connected');

        // 3. App
        addLog('Importing App...');
        setModules(m => m.map(Mod => Mod.id === 'app' ? { ...Mod, state: 'loading' } : Mod));
        await wait(500);
        setModules(m => m.map(Mod => Mod.id === 'app' ? { ...Mod, state: 'ready' } : Mod)); 
        addLog('šŸš€ App Started!');
        setStatus('done');
    };

    const wait = (ms) => new Promise(r => setTimeout(r, ms));
    const addLog = (msg) => setLogs(p => [...p, msg]);

    return (
        <div className="bg-slate-50 dark:bg-slate-950 p-8 rounded-3xl border border-slate-200 dark:border-slate-800 shadow-xl">
             <div className="flex justify-between items-center mb-10">
                <h3 className="text-2xl font-black text-gray-900 dark:text-white flex items-center gap-3">
                    <span className="text-yellow-500">ā³</span> Dependency Graph
                </h3>
                <button 
                    onClick={startLoading}
                    disabled={status === 'loading'}
                    className="bg-yellow-500 hover:bg-yellow-600 disabled:opacity-50 text-white font-bold px-6 py-2 rounded-xl transition-all flex items-center gap-2"
                >
                    {status === 'loading' ? <span className="animate-spin">ā³</span> : <span>ā–¶ļø</span>}
                    {status === 'loading' ? 'Initializing...' : 'Run Imports'}
                </button>
            </div>

            <div className="flex flex-col md:flex-row gap-8">
                
                {/* Module Tree */}
                <div className="flex-1 space-y-4">
                    {modules.map((mod, i) => (
                        <div key={mod.id} className="relative">
                            {/* Connector Line */}
                            {i < modules.length - 1 && (
                                <div className={`absolute left-6 top-10 w-1 h-8 transition-colors duration-300 ${
                                    mod.state === 'ready' && modules[i+1].state !== 'pending' ? 'bg-green-500' : 'bg-gray-200 dark:bg-slate-800'
                                }`}></div>
                            )}
                            
                            <div className={`p-4 rounded-xl border flex items-center justify-between transition-all duration-500 ${
                                mod.state === 'ready' 
                                ? 'bg-green-50 dark:bg-green-900/20 border-green-200' 
                                : mod.state === 'loading'
                                    ? 'bg-yellow-50 dark:bg-yellow-900/20 border-yellow-200 scale-105 shadow-lg'
                                    : 'bg-white dark:bg-slate-900 border-slate-200 dark:border-slate-800 opacity-60'
                            }`}>
                                <div className="flex items-center gap-4">
                                    <div className={`w-12 h-12 rounded-full flex items-center justify-center font-bold text-white transition-colors ${
                                        mod.state === 'ready' ? 'bg-green-500' : mod.state === 'loading' ? 'bg-yellow-500 animate-pulse' : 'bg-gray-300'
                                    }`}>
                                        {i + 1}
                                    </div>
                                    <div>
                                        <div className="font-bold text-gray-800 dark:text-white">{mod.name}</div>
                                        <div className="text-xs text-gray-500">
                                            {mod.state === 'ready' ? 'Module Eval Complete' : `Top-Level Await (${mod.duration}ms)`}
                                        </div>
                                    </div>
                                </div>
                                {mod.state === 'loading' && <span className="text-2xl animate-spin">ā³</span>}
                            </div>
                        </div>
                    ))}
                </div>

                {/* Console Log */}
                <div className="w-full md:w-1/3 bg-black rounded-xl p-6 font-mono text-xs overflow-y-auto h-[300px]">
                    <div className="text-gray-500 border-b border-gray-800 pb-2 mb-4 uppercase font-bold">Boot Logs</div>
                    <div className="space-y-2">
                        {logs.map((log, i) => (
                            <div key={i} className="text-green-400 animate-in slide-in-from-left-2">
                                &gt; {log}
                            </div>
                        ))}
                    </div>
                </div>

            </div>
        </div>
    );
}