The 3 Core Behaviors:

1. async = Promise Factory:

javascript

async function anything() {
    return "hello"; // Automatically becomes Promise.resolve("hello")
}
// ANY async function ALWAYS returns a promise, no exceptions

2. await = Promise Unwrapper:

let result = await somePromise; // Pauses function, extracts promise value
// Think: "Stop here, wait for promise, give me the actual value"

3. Error Transform Rule:

// These are identical:
await Promise.reject(new Error("oops")); 
throw new Error("oops");
// await converts rejected promises to thrown errors

The Mental Model - Function Transformation:

Before async/await (Promise Hell):

function getData() {
    return fetch('/user')
        .then(response => response.json())
        .then(user => fetch(`/posts/${user.id}`))
        .then(response => response.json())
        .then(posts => posts.filter(p => p.published));
}

After async/await (Readable Code):

async function getData() {
    let response = await fetch('/user');
    let user = await response.json();
    let postsResponse = await fetch(`/posts/${user.id}`);
    let posts = await postsResponse.json();
    return posts.filter(p => p.published);
}

Same behavior, but reads like synchronous code!


The await HALT Behavior:

What await actually does:

async function slowFunction() {
    console.log('Start slow');
    await new Promise(resolve => setTimeout(resolve, 3000)); // HALT HERE
    console.log('End slow'); // UNREACHABLE until await resolves
}

await = LITERAL FUNCTION PAUSE

  • Function execution STOPS at await line
  • Everything below await is unreachable until promise resolves
  • Function exits and control goes back to caller

Your Exact Scenario Breakdown:

With await (your example):

console.log('Before');        // 1. Runs first (sync)
slowFunction();               // 2. Starts function
  console.log('Start slow');  // 3. Runs (sync inside function)
  await new Promise(...);     // 4. HALT! Function pauses, exits
console.log('After');         // 5. Runs immediately (sync)
// 6. (3 seconds later) Promise resolves, function resumes
  console.log('End slow');    // 7. Finally runs

Without await (your comparison):

console.log('Before');                    // 1. Runs first
slowFunction();                           // 2. Starts function
  console.log('Start slow');              // 3. Runs
  new Promise(resolve => setTimeout(...)); // 4. Creates promise, doesn't wait
  console.log('End slow');                // 5. Runs immediately!
console.log('After');                     // 6. Runs
// Promise resolves 3 seconds later (nobody cares)

With .then (your other comparison):

console.log('Before');
slowFunction();
  console.log('Start slow');
  new Promise(resolve => setTimeout(...))
    .then(() => console.log('Promise done')); // Goes to microtask queue
  console.log('End slow');  // Runs immediately (not in .then)
console.log('After');
// Later: 'Promise done' runs

The Mental Rule:

await = Function Boundary

  • Think of await as an invisible function exit
  • Everything after await is like a .then() callback
  • Function literally stops existing until promise resolves

Visual representation:

javascript

async function test() {
    console.log('A');
    await promise;
    // ^^^ INVISIBLE WALL - function exits here
    console.log('B'); // This is like .then(() => console.log('B'))
}

The Key Difference:

await behavior:

javascript

// This code
async function f() {
    console.log('1');
    await promise;
    console.log('2'); // Waits for promise
}
 
// Behaves like this
function f() {
    console.log('1');
    return promise.then(() => {
        console.log('2');
    });
}

No await behavior:

javascript

function f() {
    console.log('1');
    promise; // Just creates promise, doesn't wait
    console.log('2'); // Runs immediately
}

Bottom Line:

await = hard stop. Think of it as the function temporarily dying at that line. Control goes back to caller, sync code continues, and the function resurrects later when the promise resolves. Everything after await is essentially a .then() callback in disguise!