Understanding the mechanics of async/await and Promise in TypeScript

Trying to wrap my head around how async, await, and promises work with this simple function.

function delay(ms: number) {
    return new Promise<void>(function(resolve) {
       setTimeout(resolve, ms);
    });
}

async function asyncAwait() {
    console.log("A");

    await delay(1000);
    console.log("B");

    await delay(1000);
    console.log("C");
}

asyncAwait();
console.log("D");

As I understand it, the expected workflow should be like this:

Call asyncAwait(); first, then print A, wait for 1 second to print B, then wait another 1 second to print C, and finally print D.

However, the output I'm seeing is:

A
D
B
C

I'm confused as to why console.log("D") is showing up second.

Could someone provide an explanation of the code above?

Appreciate any help in advance!

Answer №1

Explaining the workings of asynchronous calls:

If we look at the code execution:

function delay(ms: number) {
    return new Promise<void>(function(resolve) {
       setTimeout(resolve, ms);
    });
}

async function asyncAwait() {
    console.log("A");

    await delay(1000);
    console.log("B");

    await delay(1000);
    console.log("C");
}

asyncAwait();   // <-- 1st call
console.log("D");

Inside the function:

async function asyncAwait() {
    console.log("A");  // <--- 1st print, as it is synchronous

    await delay(1000); // <--- await
    console.log("B");  // <--- 2nd print

    await delay(1000); // <-- await
    console.log("C");  // <-- 3rd print
}

And finally,

function delay(ms: number) {
    return new Promise<void>(function(resolve) {
       setTimeout(resolve, ms);
    });
}

async function asyncAwait() {
    console.log("A");

    await delay(1000);
    console.log("B");

    await delay(1000);
    console.log("C");
}

asyncAwait();
console.log("D"); // <-- last print

However, the async function operates asynchronously. So all async calls are placed in a queue for later processing.

Initially, the synchronous calls are executed:

console.log("A");
console.log("D");

Followed by the async calls.

The await functionality only functions within an async function.

Therefore, the function:

async function asyncFunc() {
  console.log("A");

  await delay(1000);
  console.log("B");
}

Is essentially equivalent to this:

asyncFunc() {
  console.log('A');
  delay().then(()=> {
     console.log('B');
  });
}

If you wish to have the console.log("D") execute after the async function, you must await the asyncFunction. However, using await requires being within an async function:

async function asyncFunc2() {
  await asyncAwait();
  console.log("D");
}

asyncFunc2();

Answer №2

To properly execute the asyncAwait() function, you must use the await keyword:


function pause(ms: number) {
    return new Promise<void>(function(resolve) {
       setTimeout(resolve, ms);
    });
}

async function asyncAwait() {
    console.log("A");

    await pause(1000);
    console.log("B");

    await pause(1000);
    console.log("C");
}

async function start() {
    await asyncAwait();
    console.log("D");
}

start();

Answer №3

The reason for its behavior is that deep down, your code looks like this:

function similarFunction() {
    console.log("A");
    setTimeout(
        function() {
            console.log("B");
            setTimeout(
                function() {
                    console.log("C");
                }
            ,1000)
        }
    ,1000)
}

similarFunction();
console.log("D");

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

When `Omit` is applied to a type that includes an index signature, it removes all field declarations that are not part of

Currently, I am working on developing a React component that wraps around the Select component from react-select. The issue arises with a specific prop declaration that can be seen here: export type SelectComponentsProps = { [key in string]: any }; expor ...

In TypeScript, how are angle brackets like methodName<string>() utilized?

Could someone please assist me in understanding why we use angular brackets <> in typescript? For example, I have provided some code below and would appreciate an explanation. export class HomePage { constructor(public navCtrl: NavController) ...

ts-jest should replace the character '@' with the '/src' folder in the map configuration

I have set up a node project using TypeScript and configured various paths in my tsconfig.json file, such as: "paths": { /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl' ...

Staying patient while the array loads data from Firebase so that methods can be called efficiently

As an Angular newbie, I am working on a project that involves accessing data from Firebase using an Angular service. My goal is to retrieve this data, store it in an array, and then perform some operations on that array. However, due to my limited experien ...

How can I ensure that a particular component type passes the typescript check in a react-typescript project?

I'm fairly new to using TypeScript, although I have a lot of experience with React (and prop-types). Recently, I've run into an issue when it comes to typing my components, specifically when another component is passed as a prop. I already have ...

Tips for uploading images, like photos, to an iOS application using Appium

I am a beginner in the world of appium automation. Currently, I am attempting to automate an iOS native app using the following stack: appium-webdriverio-javascript-jasmine. Here is some information about my environment: Appium Desktop APP version (or ...

Error in TypeScript when using keyof instead of literal in type pattern.Beware of TypeScript error when not

let c = { [X in keyof { "foo" }]: { foo: "bar" } extends { X } ? true : false }["foo"]; let d = { foo: "bar" } extends { "foo" } ? true : false; c and d should both return true, but surprisingly, c is eval ...

What could be causing the lack of updates to my component in this todo list?

Based on my understanding, invoking an action in MobX should trigger a rerender for the observer. However, when I call the handleSubmit method in my AddTask component, it doesn't cause the TaskList observer to rerender. Should I also wrap AddTask in a ...

Retrieve data from submit button in Angular and use it as a parameter to invoke a function

I am working on a HTML file that includes a dropdown list: <select> <option *ngFor="let t of items" value="t"> {{ t }} </option> </select> In addition to the dropdown list, there ...

Using MUI DatePicker and react-hook-form to implement a date picker in the format DD/MM/YYYY

I have developed a custom datePicker component that combines react-hook-form and Material UI. However, I am encountering an issue where the values are being displayed in the format: "2024-04-10T22:00:00.000Z" Below is the code snippet: import { Localizati ...

Navigating UnwrapRefSimple in Vue Composition API and TypeScript: Best Practices

When I utilize reactive objects in Vue Composition API, I encounter Typescript errors relating to UnwrapRefSimple<T>. This issue appears to be specifically tied to using arrays within ref(). For instance: interface Group<T> { name: string ...

Ways to utilize multiple tsconfig files within VS Code

My project structure in Visual Studio Code is fairly common with a client, server, and shared directory setup: ├── client/ │ ├── tsconfig.json ├── shared/ ├── server/ │ ├── tsconfig.json ├── project.json The tw ...

What is the best way to restrict a mapped type in typescript to only allow string keys?

In the Typescript documentation, I learned about creating a mapped type to restrict keys to those of a specific type: type OptionsFlags<Type> = { [K in keyof Type]: boolean; }; If I want to use a generic type that only accepts strings as values: t ...

Assigning a specific data type to an object in TypeScript using a switch case statement

I am currently developing a React Native app using TypeScript. As part of my development, I am creating a handler with a switch case structure like the one below: export const handleMessageData = (dispatch: Dispatch, messageData: FCMMessage): void => ...

The preflight request in Angular2 is being rejected due to failing the access control check: The requested resource does not have the 'Access-Control-Allow-Origin' header

I encountered an issue while attempting to execute a basic POST request to establish an account using an API in .NET. The process fails with the mentioned warning title. Interestingly, performing the same request in Postman (an API testing tool) yields a s ...

Storing a value received from an observable into a component variable in Angular 4 using the subscribe method

I am attempting to save the value from an observable into a variable within the component by utilizing a service. However, the variable always ends up as undefined. When I check "names" inside the subscribe function, it does contain the expected value. ...

What is the recommended method for deleting sequelize.connectionManager.getConnection according to the Sequelize documentation?

I am currently developing an AWS Lambda function using Typescript that interacts with a database through Sequelize. According to the official Sequelize documentation, the configuration for Sequelize should be as follows: let sequelize = null; async func ...

How is it possible to access a variable in a function that hasn't been declared until later?

While working on a Dialog component, I had an unexpected realization. export const alert = (content: string) => { const buttons = [<button onClick={()=>closeModal()}>ok</button>] // seems alright // const buttons = [<button onCli ...

Tips for correctly passing the type of combineReducers: I encountered an error saying "Property '...' does not exist on type 'Reducer<CombinedState{}>"

I am currently integrating TypeScript into my react/redux project. Unfortunately, I am encountering an error that is preventing my app from loading. The issue is shown in the screenshot below: https://i.sstatic.net/HkPwo.png Within my index.tsx file, I a ...

Tips for efficiently utilizing mapActions in vue with Typescript class components!

Can someone please provide guidance on the correct way to use ...mapActions([]) within a Typescript vue class component? This is my current approach: <script lang="ts"> import { Component, Prop, Vue } from "vue-property-decorator"; import { mapActi ...