Promise.resolve()
ES6+Returns a Promise object that is resolved with the given value.
Syntax
Promise.resolve(value)Parameters
value any The value to resolve the promise with
Return Value
A Promise that is resolved with the given value
Examples
Promise.resolve(42)
.then(value => console.log(value)); 📌 When to Use
Use Promise.resolve() to lift plain values into the promise world so every caller can rely on one asynchronous contract. The classic case is a cache-or-fetch function: on a hit you return Promise.resolve(cachedValue), on a miss you return the fetch promise — callers simply await either way, with no type checking. It also normalizes mixed inputs: when an argument may be a value, a native promise, or any thenable (an object with a then method, common in older promise libraries), Promise.resolve(x) assimilates all three into a genuine native promise you can chain safely. It is handy in tests and mocks — stub an async dependency with () => Promise.resolve(fixture) — and as a neutral chain starter, Promise.resolve().then(step1).then(step2), when assembling pipelines dynamically. Mind the terminology: 'resolve' does not always mean 'fulfill'; resolving to a rejected promise yields a rejected promise. Also know when you do not need it: inside an async function a returned value is wrapped automatically, so return x is equivalent to return Promise.resolve(x), and awaiting a plain value already works. Prefer the explicit call at public API boundaries, where callers must receive a real promise regardless of the shortcuts taken inside.
⚠️ Common Mistakes
Sprinkling Promise.resolve() where the value never enters a chain — await 42 and return value inside async functions already behave correctly. The extra wrapper adds an allocation and a microtask hop for nothing; use it only where a promise-shaped contract must be satisfied.
Assuming it always creates a new object. Given a native promise, Promise.resolve(p) returns the exact same reference — p === Promise.resolve(p) is true — so identity-based logic can be surprised. Given a thenable from another library, however, it does create a new native promise that follows it.
Believing the result is always fulfilled. Promise.resolve(rejectedPromise) adopts the rejection — the name means 'resolve to', not 'fulfill with'. Code that treats the return value as guaranteed-successful skips error handling it still very much needs.
Forgetting that a synchronously known value still arrives asynchronously. Promise.resolve(x).then(fn) runs fn on the microtask queue, after the current code finishes — so state you expect the handler to have set is not yet set on the very next line. This zero-delay-that-is-not-zero regularly trips up developers porting synchronous code.
Calling Promise.resolve(fn()) hoping to make a synchronous function safe for async callers. If fn throws synchronously, the exception escapes before Promise.resolve() ever runs, so the caller's catch() never sees it. Use Promise.resolve().then(fn) — or an async function — when synchronous throws must be converted into rejections.
✅ Best Practices
Normalize mixed sync/async returns at API boundaries so a function's contract is 'always a promise' — callers can then compose it with await, Promise.all(), and timeout wrappers without inspecting types first.
Use Promise.resolve(input).then(...) as a safe assimilation step when accepting values from third-party code: it converts thenables from any promise library into native promises with native timing and error semantics.
In unit tests, stub asynchronous dependencies with Promise.resolve(fixture) (or your mock framework's mockResolvedValue) to keep tests deterministic and fast while preserving the real one-microtask asynchrony of production code.
For read-through caches, cache the promise rather than only the value: storing the in-flight promise from the first call deduplicates concurrent requests for the same key, and Promise.resolve keeps the hit path uniform with the miss path.
When building a pipeline from an array of steps, seed the reduction with a neutral starter: tasks.reduce((chain, task) => chain.then(task), Promise.resolve()). Every step — including the first — then runs under an identical asynchronous contract, and the same shape powers retry wrappers and middleware stacks.
⚡ Performance Notes
Promise.resolve() is among the cheapest promise operations: for a plain value it allocates a single already-fulfilled promise, and for a native promise it allocates nothing at all, returning the argument unchanged — an intentional fast path that makes defensive normalization essentially free. Thenables cost more: assimilation calls the object's then method and inserts an extra microtask tick or two before handlers observe the final value. Even 'immediate' promises pay the standard asynchrony tax, because handlers run on the microtask queue, never inline; converting a hot synchronous path to promises therefore adds a queue hop per step — only microseconds, but it also defers the work past the current call stack, which can matter for code that depends on ordering. In tight loops that create millions of pre-resolved promises, allocation pressure becomes measurable; hoist a single resolved promise into a constant and reuse it where the value does not vary.
🌍 Real World Example
Cached Data Fetcher
A read-through cache with a uniform asynchronous interface: hits return Promise.resolve(cachedValue), misses fall through to fetch, store, and return. Callers write one line — fetchData(key).then(render) — and never know or care which path executed; there is no 'sometimes sync, sometimes async' hazard because even the cache hit is delivered on the microtask queue. The pattern extends naturally to caching the in-flight promise itself, which additionally deduplicates concurrent requests for the same key while the first load is still running.
const cache = new Map();
function fetchData(key) {
if (cache.has(key)) {
return Promise.resolve(cache.get(key));
}
return fetch(`/api/${key}`)
.then(res => res.json())
.then(data => {
cache.set(key, data);
return data;
});
}
// Usage - always returns a promise
fetchData('users').then(console.log);