DEV Community

Kevin Le
Kevin Le

Posted on

44 6

Async without await, Await without async

Let's say we have a function getPromise() that returns a Promise that will resolve to some value in the future. The question is whether we need to declare it with the async keyword if we want to call it either (i) using the async/await style or (ii) using the then clause. For example, in the same code base, some time we want to call it like this:

//Snippet 1. Call using async/await
(async() => {
    try {
        const result = await getPromise("a");   
        console.log('async/await -> ', result);
    } catch (err) {
        console.log(err);
    }
})();

...and in some other time, like this:

//Snippet 2. Call using then clause
(() => {
    getPromise("b")
    .then(result => {
        console.log('then -> ', result);
    })
    .catch(err => {
        console.log(err);
    });
})();

then should we declare getPromise() like this?

//Snippet 3. Declare without async keyword
const getPromise = (s) => {  
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve(s), 500);
    });
}

...or like this?

//Snippet 4. Declare with async keyword
const getPromise = async (s) => {  
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve(s), 500);
    });
}

It turns out all of the above combinations are possible, because async/await is still Promise-based under the hood:

  1. If a function is declared with the async keyword, we can call it with the await keyword. So that's like snippet 4 (declare getPromise with async) and snippet 1 (calling with await). There should be no surprise here.

  2. But if we declare getPromise without the async keyword (snippet 3), we can still call it with the await keyword. The reason being is getpromise() returns a Promise object. If a function returns a Promise, we can call it with await. So snippet 3 and snippet 1 still work together.

  3. What about calling using the then clause? Of course, before async/await, back when we only had Promise, we declare a function without the async keyword (snippet 3) and we call it with the then clause (snippet 2). That was the way to do then. It remains possible to do so now. Again no surprise here.

  4. So can we declare getPromise() with the async keyword (snippet 4) and call it with the then clause (snippet 2) ? Yes, that works too.

  5. What's not to do is the following case. The outer function which is the caller function is declared without the async keyword. The will cause a run-time error.

const getPromise = async (s) => {    
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve(s), 500);
    });
}

//
(() => { //no async keyword here
  try {
    const result = await getPromise("a");   
    console.log('async/await -> ', result);
  } catch (err) {
    console.log(err);
  }
})();

6... but the following is OK (which is why I title the article async without await, because there's no await anywhere in here):

const getPromise = async (s) => {    
   return new Promise((resolve, reject) => {
     setTimeout(() => resolve(s), 500);
   });
}
(async() => {
    getPromise("b")
    .then(result => {
        console.log('then -> ', result);
    })
    .catch(err => {
    console.log(err);
    });
})();

7... and lastly, we call getPromise() without the await keyword. In this case, result has not yet been unwrapped, so it's still only a Promise object.

const getPromise = async (s) => {    
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve(s), 500);
  });
}

(async() => {
    try {
        const result = getPromise("a"); //no await, result has not been unwrapped   
        console.log('async/await -> ', result);
    } catch (err) {
        console.log(err);
    }
})();

Neon image

Build better on Postgres with AI-Assisted Development Practices

Compare top AI coding tools like Cursor and Windsurf with Neon's database integration. Generate synthetic data and manage databases with natural language.

Read more →

Top comments (1)

Collapse
 
kepta profile image
Kushan Joshi

This is a nice article Kevin.
Wanted to add little more about async function to complement with this article.

The async function automatically wraps the return value inside a promise. Whether you return a plain JS object or a Promise, it will be wrapped with a promise. Note: The compiler automatically flattens any nesting of promise for you.

In short if you are returning a promise in an async function, you can even let go of async and it will still work fine.

Neon image

Next.js applications: Set up a Neon project in seconds

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Get started →

👋 Kindness is contagious

Dive into this insightful write-up, celebrated within the collaborative DEV Community. Developers at any stage are invited to contribute and elevate our shared skills.

A simple "thank you" can boost someone’s spirits—leave your kudos in the comments!

On DEV, exchanging ideas fuels progress and deepens our connections. If this post helped you, a brief note of thanks goes a long way.

Okay