Leaderboard
Javascript Apr 20, 2026
Javascript Async Function Return Promise

JS Closure - What gets logged?

This is a daily Javascript challenge from the CodeShot archive. Practice your knowledge of Async Function Return Promise and improve your technical interview readiness.

async function test() {
  return 1
}
console.log(test())
A 1
B Promise { 1 }
C undefined
D Promise { <pending> }

Detailed Explanation

Why This Question Matters

If you’ve spent any time with JavaScript, you’ve probably felt the "async shock." You write a function, you return a value, and suddenly that value is wrapped in a Promise object you didn't explicitly create.

This specific challenge is a classic "gotcha" that separates people who just use async/await syntax from those who actually understand the JavaScript event loop and the Promise specification. It hits on a fundamental truth about how JavaScript handles asynchronous operations: an async function always returns a promise, regardless of what you actually return inside the body.

Getting this wrong in a real project usually leads to the dreaded [object Promise] appearing in your UI or bugs where your code continues executing before your data has actually arrived.

Understanding the Code

Let's look at the snippet:

async function test() {
  return 1
}
console.log(test())

At first glance, it looks trivial. You call test(), it returns 1, and console.log prints 1. Simple, right? Wrong.

The keyword async changes the entire behavior of the function. When you mark a function as async, JavaScript automatically wraps the return value in a resolved Promise.

Internally, the engine does something like this:
1. It sees the async keyword.
2. It executes the function body.
3. It takes the returned value (1) and wraps it in Promise.resolve(1).

So, even though you wrote return 1, the function is actually returning a Promise that is *already resolved* with the value of 1.

Crucially, console.log is a synchronous operation. It doesn't wait for the Promise to resolve. It just takes whatever the function returns—which is the Promise object itself—and prints it to the console.

Finding the Correct Answer

The correct answer is Option D: Promise { : 1 } (or simply a Promise object, depending on the environment's formatting).

Here is why the other options are wrong:

- Option A (1): This would only happen if the function were a regular synchronous function. The async keyword prevents this.
- Option B (undefined): You might see this if you forgot the return statement entirely. Since we explicitly return 1, the promise resolves to 1, not undefined.
- Option C (null): Same as above. null is a specific value; it doesn't just appear because a function is asynchronous.

To actually get the number 1 out of that function, you'd have to handle the promise:

// Option 1: Using .then()
test().then(res => console.log(res));

// Option 2: Using await (inside another async function)
const result = await test();
console.log(result);

Common Mistakes Developers Make

The most common mistake is assuming that async makes a function "wait" for something. It doesn't. async defines the return type of the function.

Another trap is the "await-less" call. I've seen plenty of senior devs accidentally call an async function without await inside a loop or a conditional. The code keeps running, the async function kicks off in the background, and by the time the promise resolves, the rest of the logic has already failed because the data wasn't there yet.

There's also a misconception that you only need async if you're using await inside the function. While that's the most common use case, adding async to a function that doesn't use await still forces it to return a promise. This is actually a useful pattern when you want to ensure a function adheres to a specific interface (like a plugin system that expects all handlers to be asynchronous).

Real-World Usage

In a production environment, you'll see this behavior most often when dealing with API wrappers or database layers.

Imagine you have a utility function that fetches a user profile. If you forget to await that call in your controller, you aren't passing the user object to your template—you're passing a Promise. Your template will then try to access user.name, but since user is actually a Promise, it returns undefined.

Another practical example is when using Array.prototype.map with async functions:

const ids = [1, 2, 3];
const results = ids.map(async (id) => await fetchUser(id));
console.log(results); 
// Output: [Promise, Promise, Promise]

Many developers expect results to be an array of users. Instead, they get an array of pending promises. To fix this, you need Promise.all():

const results = await Promise.all(ids.map(async (id) => await fetchUser(id)));

Key Takeaways

- An async function always returns a promise.
- If you return a non-promise value, JS wraps it in a resolved promise automatically.
- console.log does not wait for promises; it logs the object as it exists at that exact moment.
- To get the actual value, you must use .then() or await.
- Be careful with array methods like .map() or .forEach() when using async functions; they don't "await" the iterations.

Why this matters

Understanding Async Function Return Promise is crucial for passing technical interviews. In real-world applications, this concept often leads to subtle bugs if not handled correctly. For more details, you can always refer to the official MDN Documentation.

📝
Reviewed by CodeShot Editorial
Every challenge is code-reviewed by senior developers to ensure accuracy and real-world relevance. Learn more.

Ready for your shot?

Join thousands of developers solving one logic puzzle every morning.

Solve Today's Challenge →