This solution is generated by ChatGPT, correctness is not guaranteed.

AI solution for JavaScript Coding Question on BFE.dev
92. throttle Promises

Solution:

One approach to solve this problem is to use a queue to keep track of the pending promises, and whenever the maximum number of concurrent promises is reached, wait until some promise is resolved or rejected to start the next one.

Here is the implementation of throttlePromises function:

function throttlePromises(promises, maxConcurrency) {
  let pending = [];
  let results = [];

  const shiftPending = () => {
    const next = pending.shift();
    next && next().then(addResult).catch(addResult);
    // call next and add its result or error to results
  }

  const addResult = (result) => {
    results.push(result);
    // try to shift the next pending promise
    if (pending.length > 0) {
      shiftPending();
    }
  }

  for (let i = 0; i < promises.length; i++) {
    const promiseFactory = promises[i];
    const promiseFn = () => promiseFactory();
    // wrap the promise factory with a function that returns a promise
    pending.push(promiseFn);

    if (pending.length <= maxConcurrency) {
      shiftPending();
    }
    // if there are less than maxConcurrency items in the queue, start next immediately
  }

  return Promise.all(results);
}

The throttlePromises function takes an array of promise factories, wraps them with a function that returns a promise, and puts them in a queue pending. Whenever the number of pending promises is less than or equal to maxConcurrency, the function in pending is executed.

The addResult function is called whenever a promise is resolved or rejected, adds the result or error to the results array, and then tries to shift the next pending promise from the queue.

Finally, the function returns a promise that resolves or rejects when all promises are resolved or rejected in results.

Here is an example of usage:

const urls = [
  'https://jsonplaceholder.typicode.com/todos/1',
  'https://jsonplaceholder.typicode.com/todos/2',
  'https://jsonplaceholder.typicode.com/todos/3',
  'https://jsonplaceholder.typicode.com/todos/4',
  'https://jsonplaceholder.typicode.com/todos/5',
  'https://jsonplaceholder.typicode.com/todos/6',
  'https://jsonplaceholder.typicode.com/todos/7',
  'https://jsonplaceholder.typicode.com/todos/8',
  'https://jsonplaceholder.typicode.com/todos/9',
  'https://jsonplaceholder.typicode.com/todos/10',
]

const fetchUrls = urls.map((url) => {
  return () => fetch(url).then((res) => res.json());
});

throttlePromises(fetchUrls, 5).then((data) => {
  console.log(data); // prints an array of responses [ {...}, {...}, ... ]
}).catch((err) => {
  console.log(err); // prints the error
})

In this example, fetchUrls is an array of functions that return fetch promises for each URL. throttlePromises is called with fetchUrls and maxConcurrency = 5. The output is an array of responses in the order of urls.