Async Await

Laziness in Detail

Example: JavaScript

  • Eager execution model

  • Other languages behave similarly (C#, Python, Swift, Kotlin, etc.)

  • JavaScript calls its futures "Promises"

Rust Futures vs JavaScript Promises

async fn subtask() {
    println!("> > subtask"); (4)
}

async fn task() {
    println!("> Before subtask"); (3)
    subtask().await;
    println!("> After subtask"); (5)
}

fn main() {
    futures::executor::block_on(async {
        println!("before future"); (1)
        let future = task();
        println!("future is created"); (2)
        future.await;
        println!("future is awaited"); (6)
    });
}
async function subtask() {
  console.log("> > subtask"); (3)
}

async function task() {
  console.log("> before subtask"); (2)
  await subtask();
  console.log("> after subtask"); (5)
}

(async function main() {
  console.log("before promise"); (1)
  let promise = task();
  console.log("promise is created"); (4)
  await promise;
  console.log("promise is awaited"); (6)
})();

Eager Execution (JavaScript and many other languages)

async function subtask() {
  console.log("> > subtask"); (3)
}

async function task() {
  console.log("> before subtask"); (2)
  await subtask();
  console.log("> after subtask"); (5)
}

(async function main() {
  console.log("before promise"); (1)
  let promise = task();
  console.log("promise is created"); (4)
  await promise;
  console.log("promise is awaited"); (6)
})();
Diagram

Eager Execution (JavaScript and many other languages)

async function subtask() {
  console.log("> > subtask"); (3)
}

async function task() {
  console.log("> before subtask"); (2)
  await subtask();
  console.log("> after subtask"); (5)
}

(async function main() {
  console.log("before promise"); (1)
  let promise = task();
  console.log("promise is created"); (4)
  await promise;
  console.log("promise is awaited"); (6)
})();

Output: JavaScript

before promise

> before subtask

> > subtask

promise is created

> after subtask

promise is awaited

Eager Execution: Takeaways

  • as soon as async function is called it starts executing

  • runs till the first await point

  • inner async functions run their code, too, and stop at await

  • an async function with no await inside will execute its full body eagerly

Lazy Execution: Rust Futures

async fn subtask() {
    println!("> > subtask"); (4)
}

async fn task() {
    println!("> Before subtask"); (3)
    subtask().await;
    println!("> After subtask"); (5)
}

fn main() {
    futures::executor::block_on(async {
        println!("before future"); (1)
        let future = task();
        println!("future is created"); (2)
        future.await;
        println!("future is awaited"); (6)
    });
}
Diagram

Lazy Execution: Rust Futures

async fn subtask() {
    println!("> > subtask"); (4)
}

async fn task() {
    println!("> Before subtask"); (3)
    subtask().await;
    println!("> After subtask"); (5)
}

fn main() {
    futures::executor::block_on(async {
        println!("before future"); (1)
        let future = task();
        println!("future is created"); (2)
        future.await;
        println!("future is awaited"); (6)
    });
}

Output: Rust

before future

future is created

> Before subtask

> > subtask

> After subtask

future is awaited

Rust Futures vs JavaScript Promises

async fn subtask() {
    println!("> > subtask"); (4)
}

async fn task() {
    println!("> Before subtask"); (3)
    subtask().await;
    println!("> After subtask"); (5)
}

fn main() {
    futures::executor::block_on(async {
        println!("before future"); (1)
        let future = task();
        println!("future is created"); (2)
        future.await;
        println!("future is awaited"); (6)
    });
}

Output: Rust

before future

future is created

> Before subtask

> > subtask

> After subtask

future is awaited

Output: JavaScript

before promise

> before subtask

> > subtask

promise is created

> after subtask

promise is awaited
async function subtask() {
  console.log("> > subtask"); (3)
}

async function task() {
  console.log("> before subtask"); (2)
  await subtask();
  console.log("> after subtask"); (5)
}

(async function main() {
  console.log("before promise"); (1)
  let promise = task();
  console.log("promise is created"); (4)
  await promise;
  console.log("promise is awaited"); (6)
})();

Lazy Future Execution: Takeaways

  • no code is being run until a future is await ed

  • await triggers the whole chain to execute

  • no "fire now, await later" workflow