Skip to content
Laviyx Learn

Try

Asynchronous JavaScript Practice

Practise timers, promises, async/await, error handling and running work in parallel. Every solution has been run with Node.js and shows its real output.

Advanced6 problemsUpdated

Review first: Async Code and the Event Loop, Promises, async and await, Fetching Data from APIs, Error Handling

Most problems use this helper, which resolves with value after ms milliseconds:

JavaScript
const wait = (ms, value) => new Promise((resolve) => setTimeout(() => resolve(value), ms));
  1. 1.Predict the order

    Intermediate

    Predict the output of this code, then run it:

    JavaScript
    console.log("1");
    setTimeout(() => console.log("2"), 0);
    Promise.resolve().then(() => console.log("3"));
    console.log("4");
    Show hint

    Synchronous code first, then microtasks (promises), then timers.

    Show solution
    JavaScript
    console.log("1");
    setTimeout(() => console.log("2"), 0);
    Promise.resolve().then(() => console.log("3"));
    console.log("4");
    Output
    1
    4
    3
    2
  2. 2.A sequence with await

    Beginner

    Using wait, write an async function that prints "Boiling water", waits 30 ms, prints "Adding tea", waits 20 ms, then prints "Tea is ready".

    Show hint

    await wait(30) pauses the async function.

    Show solution
    JavaScript
    const wait = (ms, value) => new Promise((resolve) => setTimeout(() => resolve(value), ms));
    
    async function makeTea() {
      console.log("Boiling water");
      await wait(30);
      console.log("Adding tea");
      await wait(20);
      console.log("Tea is ready");
    }
    await makeTea();
    Output
    Boiling water
    Adding tea
    Tea is ready
  3. 3.Load in parallel

    Intermediate

    Load three values in parallel with wait(40, "profile"), wait(10, "orders") and wait(20, "messages"), and print the results as an array in that order.

    Show hint

    await Promise.all([...]) keeps the original order.

    Show solution
    JavaScript
    const wait = (ms, value) => new Promise((resolve) => setTimeout(() => resolve(value), ms));
    
    const results = await Promise.all([wait(40, "profile"), wait(10, "orders"), wait(20, "messages")]);
    console.log(results);
    Output
    [ 'profile', 'orders', 'messages' ]
  4. 4.Handle a rejected promise

    Intermediate

    Write getPrice(item) that resolves with 20 for "tea" after 10 ms and rejects with new Error("Unknown item: ...") for anything else. Call it for "tea" and "cake" with await inside try...catch, printing either the price or the error message.

    Show hint

    Return new Promise((resolve, reject) => ...) and catch errors where you await.

    Show solution
    JavaScript
    function getPrice(item) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          if (item === "tea") resolve(20);
          else reject(new Error(`Unknown item: ${item}`));
        }, 10);
      });
    }
    
    for (const item of ["tea", "cake"]) {
      try {
        console.log(item, await getPrice(item));
      } catch (error) {
        console.log(error.message);
      }
    }
    Output
    tea 20
    Unknown item: cake
  5. 5.Results of every request

    Intermediate

    Run wait(10, "ok") and a promise that rejects with new Error("timeout") together, and print each result's status and its value or reason message.

    Show hint

    Promise.allSettled never rejects; each result has a status.

    Show solution
    JavaScript
    const wait = (ms, value) => new Promise((resolve) => setTimeout(() => resolve(value), ms));
    
    const results = await Promise.allSettled([wait(10, "ok"), Promise.reject(new Error("timeout"))]);
    for (const r of results) {
      console.log(r.status, r.status === "fulfilled" ? r.value : r.reason.message);
    }
    Output
    fulfilled ok
    rejected timeout
  6. 6.Retry a failing operation

    Advanced

    Write retry(fn, attempts) that calls the async function fn and, if it throws, tries again, up to attempts times in total, then rethrows the last error. Test it with a function that fails twice and succeeds on the third call, printing each attempt.

    Show hint

    Loop from 1 to attempts, return await fn() inside try, and remember the error in catch.

    Show solution
    JavaScript
    async function retry(fn, attempts) {
      let lastError;
      for (let i = 1; i <= attempts; i++) {
        try {
          return await fn(i);
        } catch (error) {
          console.log(`attempt ${i} failed: ${error.message}`);
          lastError = error;
        }
      }
      throw lastError;
    }
    
    const flaky = async (attempt) => {
      if (attempt < 3) throw new Error("network error");
      return "data loaded";
    };
    
    console.log(await retry(flaky, 5));
    Output
    attempt 1 failed: network error
    attempt 2 failed: network error
    data loaded