在其他所有承诺之前等待1个承诺

时间:2020-01-03 22:33:59

标签: javascript promise

事先为模棱两可的标题道歉。

为了更好地解释这个问题-fetch-form-data.js中有两个函数看起来像...

let cachedBaseUrl;

const getBaseUrl = () => {
  if (cachedBaseUrl) return Promise.resolve(cachedBaseUrl)

  return fetch('https://some-baseurl-endpoint.com')
    .then(baseUrl => {
      cachedBaseUrl = baseUrl
      return baseUrl
    });
}

const getFormData = formId =>
  getBaseUrl()
    .then(baseUrl => fetch('https://form-data-endpoint.com'))

module.exports = {
  getFormData
}

getFormData在其他位置的循环中被导出并调用了数百次。问题是getFormData取决于getBaseUrl,因此数百次调用getFormData也会调用getBaseUrl数百次,这经常出错,因为我猜到baseUrl端点没有不喜欢这么快就被击中。

相反,我想确保getBaseUrl仅被击中一次,并让所有后续getFormDatagetBaseUrl上都调用“ wait”,然后再继续前进。

一种解决方案是在使用getBaseUrl的任何地方导出getFormDatagetFormData,等待getBaseUrl,然后根据需要多次调用getFormData 。像...

async () => {
  const baseUrl = await getBaseUrl();
  const formData = [];

  for (let form of forms) {
    formData.push(getFormData(form));
  }

  await Promise.all(formData);
  ...
}

但是,getFormData的用法遍布整个代码库。最好像当前实现一样简单地提取getBaseUrl并仅公开getFormData,但解决“等待”所有后续getFormData调用直到至少第一个{{ 1}}呼叫已解决。

我微不足道的尝试是缓存baseUrl(如上面的代码块所示),但这并没有“停止”随后的getBaseUrl个紧接着的调用,后者又调用了getBaseUrl个,因为还没有缓存任何内容

我将如何实现这样的目标?

4 个答案:

答案 0 :(得分:3)

尝试一下

let cachedBaseUrl;
const getBaseUrl = () => {
  if (cachedBaseUrl) return cachedBaseUrl
  return cachedBaseUrl = new Promise((resolve, reject) =>
      fetch('https://some-baseurl-endpoint.com')
          .then(BaseUrl => { cachedBaseUrl = undefined; resolve(BaseUrl) })
          .catch(() => { cachedBaseUrl = undefined; reject() })
  );
}

您需要在第一个请求完成之前停止getBaseUrl()发送其他请求。因此,您需要一个请求的承诺,而不是Promise.resolve(constant)

请求完成后,您可以使用resolve/reject设置其结果并重置cachedBaseUrl,以便您可以通过if并重试。

由您决定重置逻辑。您可以不停地不断地,顺序地(如现在这样)或不时地获取baseurl-endpoint,那么您将不得不调用SetTimeout(interval, () => cachedBaseUrl = undefined)而不是cachedBaseUrl = undefined。或者做你想做的事。

答案 1 :(得分:1)

也要缓存您的诺言。

let cachedBaseUrl, cachedPromise;

const getBaseUrl = () => {
  if (cachedBaseUrl) return Promise.resolve(cachedBaseUrl)
  if (cachedPromise) return cachedPromise;

  cachedPromise = fetch('https://some-baseurl-endpoint.com')
    .then(baseUrl => {
      cachedBaseUrl = baseUrl
      return baseUrl
    });

  return cachedPromise;
}

const getFormData = formId =>
  getBaseUrl()
    .then(baseUrl => fetch('https://form-data-endpoint.com'))

module.exports = {
  getFormData
}

答案 2 :(得分:0)

一次致电getBaseUrl()并保存您从中获得的承诺。然后在getFormData()中,根据已保存的承诺调用then

const getBaseUrl = () => ...

const baseUrlPromise = getBaseUrl()

const getFormData = formId =>
  baseUrlPromise
    .then(...)

在一个承诺上多次使用.then(...)可以做出多个依赖于此的承诺。

如果cachedBaseUrl没什么用,可以将其删除,因为解析后的值将保存为baseUrlPromise的一部分。

答案 3 :(得分:0)

您的缓存解决方案是一个不错的开始,通过缓存未完成的promise,我认为它可以很好地解决问题。

let cachedBaseUrl;

const getBaseUrl = () => {
  if (cachedBaseUrl) return Promise.resolve(cachedBaseUrl)
  return cachedBaseUrl = fetch('https://some-baseurl-endpoint.com');
}

const getFormData = formId =>
  getBaseUrl()
    .then(baseUrl => fetch('https://form-data-endpoint.com'))

module.exports = {
  getFormData
}