如何每隔2秒调用一次API,直到异步功能中所需的结果或超时

时间:2018-10-10 11:59:50

标签: javascript async-await es6-promise

如果响应为running,我需要每2秒调用一次api,并在响应为completefailed或直到30秒过去时首先返回并且该功能超时。

这是我现在可以使用的功能,但是我确信它可以更高效地完成工作,但是我现在还无法弄清楚:

const getStatus = async (processId) => {
  try {
    const response = await fetch(`example.com/api/getStatus/${processId}`);
    const status = await response.json();

    return await status;
  } catch(err) {
    // handle error
  }
}

使用getStatus()在另一个异步函数中:

randomFunction = async () => {
  let status = null;
  let tries = 0;
  let stop = false;

  while (tries <= 15 && !stop) {
    try {
      status = await getStatus('some-process-id');

      if (status === 'complete') {
        stop = true;
        // do something outside of loop
      }

      if (status === 'failed') {
        stop = true;
        throw Error(status);
      }

      if (tries === 15) {
        stop = true;
        throw Error('Request timed out');
      }
    } catch (err) {
      // handle error
    }

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

    if (tries < 15) {
      await delay(2000);
    }

    tries++;
  }
}

我希望以更易读的格式处理getStatus()内部的循环,但是有可能吗?

编辑: 我尝试了一种看起来更好并且似乎可以按预期工作的解决方案,请在此处查看:

https://gist.github.com/AntonBramsen/6cec0faade032dfa3c175b7d291e07bd

让我知道解决方案的某些部分是否包含任何不好的解决方案。

1 个答案:

答案 0 :(得分:0)

您的问题是关于javascript的。不幸的是我不喝咖啡,我只能给你C#中的代码。但是我想您已经精髓了,可以弄清楚如何将其翻译成Java

让我们将其作为通用函数来实现:

您有一个每个TimeSpan都被调用的函数,并且您希望在该函数返回true时停止调用该函数,而您要在经过某个最大时间后取消该函数。

在这个最长的时间内,我使用CancellationToken,这使您可以取消超时,原因更多。例如,因为操作员想要关闭程序。

TapiResult CallApi<TapiResult> <Func<TapiResult> apiCall,
    Func<TapiResult, bool> stopCriterion,
    CancellationToken cancellationToken)
{
    TapiResult apiResult = apiCall;
    while (!stopCriterion(apiResult))
    {
        cancellationToken.ThrowIfCancellationRequested();
        Task.Delay(delayTime, cancellationToken).Wait;
        apiResult = apiCall;
    }
    return apiResult;

}

  • ApiCall是要调用的Api函数。返回值为TApiResult。在您的情况下,status是您的TApiResult
  • StopCriterion是具有输入ApiResult的函数,并且在必须停止该函数时输出一个布尔值。在您的情况下,这就是status等于completefailed
  • CancellationToken是您可以从Token获得的CancellationTokenSource。每当您希望过程停止处理时,只需告诉CancellationTokenSource,函数就会以CancellationException停止

假设这是您的Api:

Status MyApiCall(int x, string y) {...}

那么用法是:

Timespan maxProcessTime = TimeSpan.FromSeconds(45);
var cancellationTokenSource = new CancellationTokenSource();

// tell the cancellationTokenSource to stop processing afer maxProcessTime:
cancellationTokenSource.CancelAfter(maxProcessTime);

// Start processing
Status resultAfterProcessing = CallApi<Status>(
   () => MyApiCall (3, "Hello World!"),        // The Api function to call repeatedly
                                               // it returns a Status
   (status) => status == complete              // stop criterion: becomes true
            || status == failed,               // when status complete or failed
   cancellationTokenSource.Token);             // get a token from the token source

待办事项:为CancellationException添加try / catch,并处理任务取消后应执行的操作

该函数将在stopCriterion变为true时或在CancellationTokenSource取消时停止。此操作将在maxTimeOut之后自动完成。但是,如果您想更早停止,例如因为要停止程序,就可以:

cancellationTokenSource.Cancel();