【问题标题】:Keep calling an API every 2.5 seconds and close the call once desired result is achieved保持每 2.5 秒调用一次 API,并在达到所需结果后关闭调用
【发布时间】:2020-10-12 16:49:05
【问题描述】:

我有一个 API 每 2.5 秒调用一次。最初,响应对象中的数据为空,因为数据库仍在通过事务对其进行更新。但在随后的第 3 次或第 4 次尝试中,我得到了数据。我正在为此编写一个可重用的函数,但是我没有定义。我的目标是继续调用 API,直到我获得路径中的值并关闭连接。请指教。

P.S:下面的 API URL 没有任何延迟,但我的私有 API 有。

const getData = (url, path) => {
  const interval = setInterval(async () => {
    const result = await axios.get(url);
    if (_.has(result.data, path) && result.data[path]) {
      return result[path]
    }
  }, 2500)
  return clearInterval(interval)
}

getData('https://api.oceandrivers.com/static/resources.json', 'swaggerVersion')
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>

JS Fiddle URL

请指教。

【问题讨论】:

  • 因为 JS 是异步的,你正在清除间隔。没有像线性编程语言那样的块(大多数时候)。

标签: javascript async-await setinterval


【解决方案1】:

return clearInterval(interval); // undefined

如果你想返回一个在数据可用时解决的 Promise,你可以这样做:

const getData = (url, path) => {
  return new Promise((resolve, reject) => {
    const interval = setInterval(async() => {
      const result = await axios.get(url);
      if (_.has(result.data, path) && result.data[path]) {
        clearInterval(interval); // Clear the interval
        resolve(result.data[path]); // Resolve with the data
      }
    }, 2500);
  });
}

getData('https://api.oceandrivers.com/static/resources.json', 'swaggerVersion')
  .then(data => {
    console.log(data); // Your data is available here
  });

// OR

(async () => {
  const version = await getData('https://api.oceandrivers.com/static/resources.json', 'swaggerVersion');
  console.log(version);
})();

【讨论】:

  • 我仍然不确定:jsfiddle.net/ftjgazbe
  • 啊,对,应该是resolve(result.data[path]);jsfiddle.net/kcw1vsjq
  • 谢谢伙计。有没有办法直接从函数本身返回数据,而不是我在 getData 上做 .then ?
  • @a2441918 当然,您可以使用IIFEsetTimeout 创建一个循环:jsfiddle.net/2k8z5wyn
  • 为了能够从其他地方使用clearTimeout(关闭模式的函数),超时需要在getData函数之外可用。下面是一个例子(别看我对axios和console.log做了什么,这只是为了演示)jsfiddle.net/a3o5myhb
【解决方案2】:

这是因为 javascript 是异步的,因为上面的评论已经提到过。您可以在 javascript 中使用回调或承诺。代码如下:

const getData = (url, path, cb) => {
  const interval = setInterval(async () => {
    const result = await axios.get(url);
    if (_.has(result.data, path) && result.data[path]) {
     clearInterval(interval); //We found it remove the interval
      cb(result.data[path]);
    }
  }, 2500);
};

getData(
  "https://api.oceandrivers.com/static/resources.json",
  "swaggerVersion",
  data => {
    console.log("test",data);
  }
);

这里是小提琴:https://jsfiddle.net/7pc4hq6t/3/

【讨论】:

  • 谢谢哥们。有没有办法直接从函数本身返回数据,而不是我在 getData 上做 .then ?
  • 不,因为 javascript 在不同的线程上运行它。当这个结果出现时,它需要某种类型的通信来了解它完成的代码。因此,您可以使用承诺或回调。
  • 有没有办法立即触发 API 调用,然后第二次尝试等待 2.5 秒?
  • 看看你可以为 API 创建 fetch 函数。作为 dom 加载尝试点击该 API。并在 setinterval 检查数据是否不可用再次点击 API。我建议不要自己处理所有情况,而是尝试 asyncjs[caolan.github.io/async/v3/].它肯定会对你有很大帮助。
【解决方案3】:

你可以创建一个异步延迟:

const delay = milliseconds => new Promise(resolve, setTimeout(resolve, milliseconds));

然后像这样使用:

const getDataAsync = async (url, path) => {
    while (true) {
        const result = await axios.get(url);
        if (_.has(result.data, path) && result.data[path]) {
            return result.data[path];
        }
        await delay(2500);
    }
}

const data = await getDataAsync('https://api.oceandrivers.com/static/resources.json', 'swaggerVersion');

这避免了多层嵌套回调,并生成更易读的代码。

【讨论】:

  • @a2441918 当第一个 await 被命中时,async 函数隐式返回 PromisePromise 在您返回某些内容时得到解决(或在抛出错误时被拒绝)。 async / await 本质上是 Promise-returning 方法的语法糖。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-04-21
  • 1970-01-01
  • 2017-02-01
  • 2015-05-28
  • 1970-01-01
  • 1970-01-01
  • 2021-08-22
相关资源
最近更新 更多