core-js provides a complete Promise polyfill including the constructor, all static combinators, prototype methods, and two finished proposals: Promise.try and Promise.withResolvers.
Import
import 'core-js/actual/promise';
Or import individual methods:
import 'core-js/actual/promise/all-settled';
import 'core-js/actual/promise/any';
import 'core-js/actual/promise/finally';
import 'core-js/actual/promise/try';
import 'core-js/actual/promise/with-resolvers';
Constructor
const promise = new Promise((resolve, reject) => {
setTimeout(() => resolve(42), 1000);
});
The executor runs synchronously. Call resolve to fulfill or reject to reject the promise.
Prototype methods
then
Attaches handlers for fulfillment and/or rejection. Returns a new promise.
new Promise((resolve, reject) => {
setTimeout(resolve, 5000, Math.random() * 1000 | 0);
})
.then(result => {
console.log(result); // e.g. => 869, after 5 sec
return new Promise(resolve => setTimeout(resolve, 1000, result * 2));
})
.then(result => {
console.log(result); // => previous value doubled
})
.catch(error => console.log(error));
catch
Syntactic sugar for .then(undefined, onRejected).
Promise.reject(new Error('oops'))
.catch(error => console.log(error.message)); // => 'oops'
finally
Runs a callback when the promise settles (fulfilled or rejected) without changing the settled value.
Promise.resolve(42)
.finally(() => console.log('always runs'))
.then(x => console.log(x)); // => 42
Promise.reject(new Error('fail'))
.finally(() => console.log('always runs'))
.catch(e => console.log(e.message)); // => 'fail'
Static methods
Promise.resolve / Promise.reject
Wrap a value in an already-settled promise.
Promise.resolve(42).then(x => console.log(x)); // => 42
Promise.reject(new Error('bad')).catch(e => console.log(e.message)); // => 'bad'
// Wraps a thenable (e.g. jQuery Deferred) in a native Promise:
Promise.resolve($.getJSON('/data.json')).then(data => console.log(data));
Promise.all
Waits for all promises to fulfill. Rejects immediately if any promise rejects.
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
Promise.all([
'immediate value',
sleep(5000).then(() => 'after 5s'),
sleep(10000).then(() => 'after 10s'),
]).then(([a, b, c]) => {
console.log(a, b, c); // => 'immediate value', 'after 5s', 'after 10s'
});
Promise.race
Settles with the first promise to settle (fulfilled or rejected).
function timeLimit(promise, seconds) {
return Promise.race([
promise,
new Promise((_, reject) =>
setTimeout(reject, seconds * 1000, new Error(`Timeout after ${seconds}s`))
),
]);
}
timeLimit(sleep(5000).then(() => 'done'), 10)
.then(x => console.log(x)); // => 'done', after 5s
timeLimit(sleep(15000).then(() => 'done'), 10)
.catch(e => console.log(e.message)); // => 'Timeout after 10s'
Promise.allSettled
Waits for all promises to settle and returns an array of outcome descriptors. Never rejects.
Promise.allSettled([
Promise.resolve(1),
Promise.reject(2),
Promise.resolve(3),
]).then(results => console.log(results));
// => [
// { status: 'fulfilled', value: 1 },
// { status: 'rejected', reason: 2 },
// { status: 'fulfilled', value: 3 },
// ]
Promise.any
Fulfills with the first promise to fulfill. Rejects with an AggregateError only if every promise rejects.
Promise.any([
Promise.resolve(1),
Promise.reject(2),
Promise.resolve(3),
]).then(console.log); // => 1
Promise.any([
Promise.reject(1),
Promise.reject(2),
Promise.reject(3),
]).catch(({ errors }) => console.log(errors)); // => [1, 2, 3]
Promise.try (ES2025)
Calls a function and always returns a promise — useful when you don’t know whether a function is synchronous or asynchronous.
import 'core-js/actual/promise/try';
// Sync function, returns fulfilled promise:
Promise.try(() => 42)
.then(it => console.log(`resolved as ${it}`));
// => 'resolved as 42'
// Sync function that throws, returns rejected promise:
Promise.try(() => { throw new Error('42'); })
.catch(error => console.log(`rejected as ${error}`));
// => 'rejected as Error: 42'
// Async function, passes through naturally:
Promise.try(async () => 42)
.then(it => console.log(`resolved as ${it}`));
// => 'resolved as 42'
// Passes additional arguments to the function:
Promise.try(it => it, 42)
.then(it => console.log(`resolved as ${it}`));
// => 'resolved as 42'
Promise.try eliminates the need for a try/catch wrapper around code that might be sync or async. It ensures consistent promise-based error handling regardless of whether the callback throws synchronously.
Promise.withResolvers (ES2024)
Returns an object containing a promise and its resolve/reject functions, so you can resolve the promise from outside the executor.
import 'core-js/actual/promise/with-resolvers';
const { promise, resolve, reject } = Promise.withResolvers();
resolve(42);
promise.then(console.log); // => 42
A common pattern is exposing a deferred promise to external code:
function createDeferred() {
return Promise.withResolvers();
}
const deferred = createDeferred();
// Some other code settles it later:
setTimeout(() => deferred.resolve('ready'), 1000);
deferred.promise.then(value => console.log(value)); // => 'ready', after 1s
Async/await compatibility
The core-js Promise polyfill is fully compatible with async/await syntax when transpiled.
async function run() {
console.log('Start');
const result = await new Promise(resolve =>
setTimeout(resolve, 5000, Math.random() * 1000 | 0)
);
console.log(result); // => e.g. 936, after 5s
const [a, b, c] = await Promise.all([
new Promise(resolve => setTimeout(resolve, 5000, 'a')),
new Promise(resolve => setTimeout(resolve, 15000, 'b')),
new Promise(resolve => setTimeout(resolve, 10000, 'c')),
]);
console.log(a, b, c); // => 'a', 'b', 'c', after 15s
}
run().catch(console.error);
Unhandled rejection tracking
In Node.js, core-js fires standard unhandledRejection and rejectionHandled events:
process.on('unhandledRejection', (reason, promise) =>
console.log('unhandled', reason, promise)
);
process.on('rejectionHandled', promise =>
console.log('handled', promise)
);
const p = Promise.reject(42);
// => unhandled 42 [object Promise]
setTimeout(() => p.catch(() => {}), 1000);
// => handled [object Promise]
In browsers, the same events fire on globalThis:
globalThis.addEventListener('unhandledrejection', e =>
console.log('unhandled', e.reason, e.promise)
);
globalThis.addEventListener('rejectionhandled', e =>
console.log('handled', e.reason, e.promise)
);