Javascript Polyfill: Promise

amit
3 min readDec 11, 2022

--

Promises are an important part of the JavaScript language, providing a way to handle asynchronous operations and make them easier to work with. In some cases, however, older browsers may not support promises natively, requiring the use of a polyfill to add this functionality.

thumbnail

In a promise-based system, a piece of code that needs to perform an asynchronous operation (such as making an API call or reading from a file) will return a promise instead of the final result. The calling code can then use the .then() method on the promise to specify a callback function that will be executed once the asynchronous operation is complete and the promise has been resolved.

Here’s a simple example of how a promise might be used in JavaScript:

// Function that returns a promise
function getDataFromAPI() {
return new Promise((resolve, reject) => {
// Perform asynchronous operation (e.g. make API call)
// If operation is successful, call resolve() with the result
// If operation fails, call reject() with the error
});
}

// Call the function and use the .then() method to specify a callback
getDataFromAPI()
.then((result) => {
// Do something with the result
})
.catch((error) => {
// Handle the error
});

A polyfill for promises typically consists of a implementation of the Promise object and its methods, such as then(), catch(), and resolve(), that can be used in place of the native implementation. This allows code that uses promises to run on platforms or browsers that do not natively support them.

Here’s an example of how a polyfill for promises might be used in JavaScript:

if (!window.Promise) {
window.Promise = function(executor) {
this.state = 'pending';
this.value = undefined;
this.resolveCallbacks = [];
this.rejectCallbacks = [];

const resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.resolveCallbacks.forEach(cb => cb(value));
}
};

const reject = value => {
if (this.state === 'pending') {
this.state = 'rejected';
this.value = value;
this.rejectCallbacks.forEach(cb => cb(value));
}
};

try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
};

window.Promise.prototype.then = function(onFulfilled, onRejected) {
const promise2 = new window.Promise((resolve, reject) => {
if (this.state === 'fulfilled') {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolve(x);
} catch (e) {
reject(e);
}
});
}
if (this.state === 'rejected') {
setTimeout(() => {
try {
const x = onRejected(this.value);
resolve(x);
} catch (e) {
reject(e);
}
});
}
if (this.state === 'pending') {
this.resolveCallbacks.push(() => {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolve(x);
} catch (e) {
reject(e);
}
});
});
this.rejectCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.value);
resolve(x);
} catch (e) {
reject(e);
}
});
});
}
});
return promise2;
};

window.Promise.prototype.catch = function(onRejected) {
return this.then(null, onRejected);
};
}

Promises are an important tool for managing asynchronous code, as they allow for a more structured and readable approach than using callback functions. Additionally, promises can be composed and chained together, making it easier to build complex asynchronous logic without ending up with a “callback hell” of nested functions.

If you liked this article, don’t forget to leave a clap and follow!

--

--

amit
amit

Written by amit

Building user-friendly & scalable products. Specializing in Javascript frameworks. Traveler & outdoor enthusiast. Open to connections & collaborations

No responses yet