Q21: Implement a polyfill for Promise.race().
Answer
Promise.race() returns a promise that settles as soon as one of the input promises settles. The first settlement may be either fulfillment or rejection.
if (!Promise.myRace) {
Promise.myRace = function (iterable) {
return new Promise((resolve, reject) => {
let iterator;
try {
iterator = iterable[Symbol.iterator]();
} catch (error) {
reject(error);
return;
}
try {
while (true) {
const step = iterator.next();
if (step.done) {
break;
}
Promise.resolve(step.value).then(resolve, reject);
}
} catch (error) {
reject(error);
}
});
};
}
Promise.myRace([
new Promise(resolve => setTimeout(() => resolve("slow"), 200)),
new Promise(resolve => setTimeout(() => resolve("fast"), 50))
]).then(console.log);
// fast
Explanation
Each input is passed through Promise.resolve(). The first fulfillment or rejection that settles the outer promise determines its outcome. Later settlements have no effect on the already-settled promise.
An empty iterable leaves the returned promise pending forever. Exact native compatibility requires careful handling of iterator closing, constructor semantics, and abrupt completion.
Key Takeaways
- Promise.race settles according to the first input to settle.
- The winning input may fulfill or reject, and an empty iterable leaves the promise pending.