Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

86
Visualizações
Given list of API end points and it's priority, returns the API response with high priority

I got this question in an interview. A weather API endpoint can return the weather data for Pincode, city, state, and country.

Given a list of APIs and their priorities, call them parallelly and return the data for the API, which has high priority.

APIs = [
  { url: "api.weather.com/pin/213131", priority: 0 },
  { url: "api.weather.com/state/california", priority: 2 },
  { url: "api.weather.com/city/sanfrancisco", priority: 1 },
  { url: "api.weather.com/country/usa", priority: 3 },
];

In the above list, the priority order is pin > city > state > country. This means calling all the APIs parallelly; if the API with Pincode returned the data first, resolve the Promise immediately; if not, it should resolve the next higher priority one.

I thought of Promise.race(), but that won't consider a priority. Then I thought of waiting till a timeout occurs, and below is my code for the same. It simply waits till timeout, and if the high priority one is resolved first, then the real Promise will be resolved. After a specific timeout, it simply resolves with the first high priority response. But the interviewer wants me to implement it without a timeout.

Below is the code with a timeout. Does anyone know how to implement it without a timeout and more generic fashion?

function resolvePromiseWithPriority(APIS, timeout) {
  let PROMISES = APIS.sort((a, b) => a.priority - b.priority).map((api) => {
    return () =>
      new Promise((resolve, reject) => {
        fetch(api.url)
          .then((data) => resolve(data))
          .catch((err) => reject(err));
      });
  });

  let priorities = [...APIS.map((item) => item.priority)];
  let maxPriority = Math.min(...priorities);
  let minPriority = Math.max(...priorities);

  let results = [];
  let startTime = Date.now();

  return new Promise((resolve, reject) => {
    PROMISES.forEach((promise, priority) => {
      promise()
        .then((data) => {
          results[priority] = data;
          let gap = (Date.now() - startTime) / 1000;

          if (gap > timeout) {
            // resolve the current high priority promise, if no promises resolved before the timeout, resolve the first one resolved.
            // If all promises are rejected, reject this promise.

            if (!results[minPriority] instanceof Error)
              resolve(resolve[minPriority]);

            for (let item of results) {
              if (!item instanceof Error) resolve(item);
              reject("No promises resolved !!");
            }
          } else {
            if (priority === maxPriority) {
              // if the high priority promise gets it's data, resolve immediately.
              resolve(results[priority]);
            }

            if (priority < minPriority) {
              minPriority = priority;
            }
          }
        })
        .catch((err) => {
          results[priority] = err;
        });
    });
  });
}
about 4 years ago · Juan Pablo Isaza
3 Respostas
Responde à pergunta

0

On the understanding that ...

Given a list of APIs and their priorities, call them parallelly and return the data for the API, which has high priority.

expands to ...

Given a list of APIs and their priorities, call them in parallel and return the data from the highest priority API that successfully delivers data; if no API is successful, then provide a custon Error.

then you neither want nor need a timeout, and the requirement can be met with three Array methods .sort(), .map() and .reduce() as follows:

function resolvePromiseWithPriority(APIS) {
    return APIS
        .sort((a, b) => a.priority - b.priority); // sort the APIS array into priority order.
        .map(api => fetch(api.url)) // initialte all fetches in parallel.
        .reduce((cumulativePromise, fetchPromise) => cumulativePromise.catch(() => fetchPromise); // build a .catch().catch().catch()... chain
    }, Promise.reject()) // Rejected promise as a starter for the catch chain.
    .catch(() => new Error('No successful fetches')); // Arrive here if none of the fetches is successful.
}

The .sort() and .map() methods are fully described by comments in the code.

The catch chain formed by the .reduce() method works as follows:

  • the starter Promise is immediately caught and allows the Pincode fetch a chance of providing the required data.
  • if fetch failure (Pincode or otherwise) gives the next highest priority fetch a chance of providing the required data, and so on, and so on, down the chain.
  • as soon as a successful fetch is encountered, the chain adopts its success path; all further catches in the chain are bypassed; with no thens anywhere in the chain, the promise returned by resolvePromiseWithPriority() delivers the successful fetch's data; any lower priority successes are effectively ignored as they would only ever be considered in the (bypassed) catches;
  • if all of the fetches fail, a terminal catch injects your custom 'No promises resolved' error.
about 4 years ago · Juan Pablo Isaza Relatório

0

Here's what I came up with:

function resolvePromiseWithPriority(apis) {
    const promises = apis
        .sort((a, b) => a.priority - b.priority)
        .map(api => fetch(api.url).then(res => res.ok ? res.json() : Promise.reject(res.status));
    const contenders = [];
    let prev = null;
    for (const promise of promises) {
        prev = Promise.allSettled([
            prev ?? Promise.reject(),
            promise
        ]).then(([{status: prevStatus}])  => {
            if (prevStatus == 'rejected') return promise;
            // else ignore the promise
        });
        contenders.push(prev);
    }
    return Promise.any(contenders);
}

The contenders wait for all previous promises (those with a higher priority) and resolve (to the same result as the current promise) only once all those rejected. Then they're passed into Promise.any, which will go with the result of the first contender to fulfill, or an AggregateError of all request failures in order of priority.

Notice a contender fulfills to undefined if any of the previous promises did fulfill, but this doesn't really matter - Promise.any would go with the first one. The code would work also with Promise.allSettled([prev, promise]).then(() => promise), but imo checking prevStatus makes the intention a bit clearer.

The usage of Promise.allSettled (over prev.then(() => promise, () => promise)) and Promise.any ensures that the code causes no unhandled rejections.

about 4 years ago · Juan Pablo Isaza Relatório

0

Assuming you already have requests promises sorted by the priority field in sortedPromises array we just need to get the result of the first successful request:

function getFirstSuccessfulResponse(sortedPromises) {
  let response = null;
  for (const promise of sortedPromises) {
    try {
      response = await promise;
      return response;
    } catch (err) {
      console.warn('Could not get data from the request')
    }
  }
}
about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda