首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >给定API端点列表及其优先级,返回具有高优先级的API响应

给定API端点列表及其优先级,返回具有高优先级的API响应
EN

Stack Overflow用户
提问于 2022-03-19 16:15:01
回答 3查看 120关注 0票数 0

我在一次面试中得到了这个问题。天气API端点可以返回Pincode、city、state和country的天气数据。

给出API及其优先级的列表,并行调用它们并返回API的数据,具有高优先级的

代码语言:javascript
复制
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 },
];

在上面的列表中,优先级顺序是pin > city > state > country。这意味着并行调用所有API;如果带有Pincode的API首先返回数据,则立即解析承诺;如果没有,则应该解决下一个更高优先级的API。

我想到了Promise.race(),但这并不是优先考虑的问题。然后我想等到超时发生,下面是相同的代码。它只是在等待超时,如果先解决高优先级的问题,那么真正的承诺就会被解决。在一个特定的超时之后,它只需使用第一个高优先级的响应来解决。但是面试官想让我在没有暂停的情况下实现它。

下面是带有超时的代码。有人知道如何在没有超时和更一般的方式的情况下实现它吗?

代码语言:javascript
复制
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;
        });
    });
  });
}
EN

回答 3

Stack Overflow用户

发布于 2022-03-20 02:40:16

据了解..。

给出了API及其优先级的列表,并行调用它们并返回具有高优先级的API的数据。

扩展到..。

给出了API及其优先级的列表,并行调用它们,并从成功传递数据的最高优先级API返回数据;如果没有API成功,则提供一个custon错误。

然后,您既不需要也不需要超时,并且可以使用三个数组方法( .sort().map().reduce() )满足需求,如下所示:

代码语言:javascript
复制
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.
}

代码中的注释充分描述了.sort().map()方法。

.reduce()方法形成的catch链工作如下:

  • 最初的承诺立即被抓住,并允许Pincode获取提供所需数据的机会。如果提取失败(Pincode或其他方式),
  • 给下一个最高优先级的获取机会,以提供所需的数据等等。
  • 一旦成功获取,该链就采取其成功的路径;链中的所有进一步捕获都被绕过;在链中任何地方都没有,resolvePromiseWithPriority()返回的承诺提供了成功的提取数据;任何低优先级的成功实际上都会被忽略,因为它们只会在(旁路)捕获中被考虑;如果所有的获取都失败,则终端捕获将注入自定义的“无承诺解决”错误。
票数 0
EN

Stack Overflow用户

发布于 2022-03-20 17:21:02

我想出的是:

代码语言:javascript
复制
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);
}

contenders等待所有previous承诺(具有较高优先级的ious)并解决(与当前promise相同的结果),只有一次所有拒绝。然后,它们被传递到Promise.any中,这将与第一个实现的竞争者的结果一致,或者按照优先级顺序对所有请求失败的AggregateError进行排序。

请注意,如果前面的承诺中有任何一个实现了undefined,那么竞争者就会履行fulfill,但这并不重要-- Promise.any将与第一个承诺一起使用。该代码也适用于Promise.allSettled([prev, promise]).then(() => promise),但海事组织检查prevStatus使其意图更加明确。

Promise.allSettled (overprev.then(() => promise, () => promise))和Promise.any的使用确保代码不会导致未处理的拒绝。

票数 0
EN

Stack Overflow用户

发布于 2022-03-21 06:48:24

假设您已经有了按priority字段排序的sortedPromises数组中的请求承诺,我们只需要获得第一个成功请求的结果:

代码语言:javascript
复制
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')
    }
  }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71539859

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档