JavaScript Promises — What Does This Output?
This is a daily Javascript challenge from the CodeShot archive. Practice your knowledge of Promise Resolves Only Once and improve your technical interview readiness.
const promise = new Promise((resolve) => {
resolve(1)
resolve(2)
resolve(3)
})
promise.then(v => console.log(v))
Detailed Explanation
Why This Question Matters
If you’ve spent any time with JavaScript, you know that Promises are the backbone of almost everything we do—from fetching API data to handling file uploads. But there's a common misconception that Promises behave like streams or arrays.
Many developers assume that if you call resolve() multiple times, the Promise will just keep firing events or "push" multiple values into the .then() block. This snippet is a classic "gotcha" question in technical interviews because it tests whether you actually understand the Promise lifecycle or if you're just guessing based on how async/await looks.
Understanding the Code
Let's look at the snippet again:
At first glance, it looks like we're telling the Promise to resolve three different times with three different numbers. You might expect the console to print 1, 2, and 3 in sequence.
But here is how the JavaScript engine actually handles this. When you create a new Promise, you provide an executor function. This function runs immediately. Inside that executor, the first time resolve(1) is called, the Promise changes its state from pending to fulfilled.
Once a Promise hits the "fulfilled" (or "rejected") state, it is locked. It becomes immutable. This is a core design principle of Promises: they represent a *single* eventual completion of an asynchronous operation.
When the engine hits resolve(2) and resolve(3), it doesn't throw an error, but it completely ignores them. The Promise has already settled. It's like trying to change the result of a race after the finish line has already been crossed; it doesn't matter who else comes in—the winner is already decided.
Finding the Correct Answer
The correct answer is 1.
Here is why the other options are wrong:
Observable (like in RxJS) or an EventEmitter. Promises are not streams; they are single-value containers.resolve() call "overwrites" the previous ones. That's not how it works. The first call to settle the promise wins.The .then() callback is triggered as soon as the Promise settles. Since it settled at 1, that's the only value that ever gets passed to the console.
Common Mistakes Developers Make
The biggest mistake is confusing Promises with Observables. If you're coming from a background in Angular or using libraries like RxJS, you're used to streams that emit multiple values over time. Switching back to vanilla JS Promises can lead to this exact mental trip-up.
Another common mistake is thinking that resolve() is like a return statement. In a normal function, return exits the function immediately. But resolve() is just a function call. The rest of the code in the executor block continues to run. If you had a console.log("Done!") after those three resolve calls, it would still print to the console, even though the Promise is already finished.
Real-World Usage
In a production environment, you'll rarely write a Promise that calls resolve three times on purpose. However, this behavior is critical when dealing with race conditions or timeouts.
Imagine you're implementing a request timeout:
In this scenario, if fetchData() finishes in 2 seconds, the Promise resolves with the data. When the 5-second timeout finally hits and calls reject(), the Promise ignores it because it's already fulfilled. This "settle once" guarantee is exactly what makes Promises predictable and reliable for managing complex async flows.
Key Takeaways
resolve or reject are silently ignored.resolve() doesn't stop the execution of the remaining code in the Promise constructor.AsyncIterators or libraries like RxJS.Why this matters
Understanding Promise Resolves Only Once 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.