From 3cc5cb77cd37218cae3a7c30c5b93f3a3c7b99dd Mon Sep 17 00:00:00 2001 From: Shaban-Eissa Date: Tue, 4 Jun 2024 22:18:46 +0300 Subject: [PATCH] feat: implement Promise.any() --- 34.implement-Promise.any.md | 122 ++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 34.implement-Promise.any.md diff --git a/34.implement-Promise.any.md b/34.implement-Promise.any.md new file mode 100644 index 0000000..7a2ea2a --- /dev/null +++ b/34.implement-Promise.any.md @@ -0,0 +1,122 @@ +# 34. implement `Promise.any()` +Promise.any is a method in JavaScript used to handle multiple promises concurrently, but with a different behavior compared to Promise.all. It returns a single promise that resolves as soon as any of the promises in the iterable fulfills, or rejects if all the promises reject. + +### Key Features of `Promise.any` + +1. **Concurrent Execution**: + + * `Promise.any` runs multiple promises in parallel. + * It resolves as soon as one of the promises fulfills. +2. **Resolved Value**: + + * When the first promise fulfills, `Promise.any` resolves with the value of that promise. + * Example: `Promise.any([promise1, promise2]).then((value) => { console.log(value); });` + * If `promise1` fulfills with `value1`, the output will be `value1`. +3. **Rejection Handling**: + + * If all promises in the iterable reject, `Promise.any` rejects with an `AggregateError`, which is a new error type that groups multiple individual errors. + * Example: `Promise.any([promise1, promise2]).catch((error) => { console.log(error); });` + * If both `promise1` and `promise2` reject, `Promise.any` will reject with an `AggregateError` containing all the rejection reasons. + + +### Problem + +https://bigfrontend.dev/problem/implement-Promise-any + +# + +### Problem Description + +> Promise.any() takes an iterable of Promise objects and, as soon as one of the promises in the iterable fulfils, returns a single promise that resolves with the value from that promise + +from [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/any) + +Can you implement a `any()` to work the same as `Promise.any()`? + +**note** + +`AggregateError` is not supported in Chrome yet, but you can still use it in your code since we will add the Class into your code. Do something like following: + +```js +new AggregateError('No Promise in Promise.any was resolved', errors); +``` + +# + +### Solution + +```js +/** + * @param {Array} promises + * @return {Promise} + */ +function any(promises) { + if (promises.length === 0) { + return Promise.resolve(); + } + + let isFulfilled = false; + const errors = Array(promises.length); + let numOfErrors = 0; + + return new Promise((resolve, reject) => { + promises.forEach((promise, i) => { + if (!(promise instanceof Promise)) { + promise = Promise.resolve(promise); + } + + promise.then( + (value) => { + if (isFulfilled) { + return; + } + + resolve(value); + isFulfilled = true; + }, + (reason) => { + errors[i] = reason; + numOfErrors++; + + if (numOfErrors === promises.length) { + reject( + new AggregateError( + 'No Promise in Promise.any was resolved', + errors + ) + ); + } + } + ); + }); + }); +} +``` + +### Example Usage + +```javascript +const promise1 = new Promise((resolve, reject) => setTimeout(reject, 100, 'Error1')); +const promise2 = new Promise((resolve, reject) => setTimeout(resolve, 200, 'Success!')); +const promise3 = new Promise((resolve, reject) => setTimeout(reject, 300, 'Error3')); + +Promise.any([promise1, promise2, promise3]) + .then((value) => { + console.log(value); // 'Success!' + }) + .catch((error) => { + console.error('All promises were rejected:', error); + }); +``` + +### Use Cases + +* **Race to Success**: When you want to proceed as soon as any one of several asynchronous operations succeeds, such as loading the fastest resource among several mirrors. +* **Fault Tolerance**: When you want to use the first available data and ignore the rest, improving fault tolerance in case some promises fail. + +### Important Notes + +* If the iterable passed to `Promise.any` is empty, it returns a promise that will be rejected with an `AggregateError`. +* If all promises reject, the rejection reason is an `AggregateError` containing an array of all rejection reasons. + +By using `Promise.any`, developers can efficiently handle scenarios where the first successful completion of any among several asynchronous tasks is sufficient, thereby enhancing performance and reliability in cases where multiple potential sources or paths are available. \ No newline at end of file