异步等待多个setIntervals

时间:2019-06-10 19:36:25

标签: javascript async-await

我有两个API请求,一个每5000毫秒调用一次,一个每30000毫秒调用一次。我要确保在向服务器发出新请求之前完成每个调用。我不希望任何一个请求都相互重叠。例如,如果func1 API尚未完成,那么在该函数完成之前,我不想发出func2 API调用。

这是我到目前为止尝试过的。

DOMPoint

这里是func1和func2。

async function vals() {
            try {
                await func1()
                    .then(response => response.json())
                    .then(result => display_result(result))
                    .catch(error => console.error('Error: ', error));
                await func2()
                    .then(response => response.json())
                    .then(result => display_result(result))
                    .catch(error => console.error('Error: ', error));
            }
            catch(error) {
                return error;
            }
}

vals();

我希望它先运行func1(),等待它解决,然后再运行func2()。相反,func1()被调用两次,并且从不访问func2()。应该将setIntervals设置在vals()函数内部吗?任何进行这项工作的指导将不胜感激。

1 个答案:

答案 0 :(得分:1)

好吧,这有点棘手!您有两个不同的时间间隔生成任务(http请求),它们花费的时间很短,并且您要确保任务彼此不重合。

我建议不要在超时后立即激活您的请求,而应将请求添加到待完成的工作队列中。该队列将尽可能快地串行处理许多任务。

// In your example your "long-running-tasks" are http requests.
// In this example I'll use a timeout.
let genLongRunningTask1 = async () => {
  console.log('Task 1 start');
  await new Promise(r => setTimeout(r, 1500));
  console.log('Task 1 end');
};

let genLongRunningTask2 = async () => {
  console.log('Task 2 start');
  await new Promise(r => setTimeout(r, 1600));
  console.log('Task 2 end');
};

// The tail of the promise-queue. If it resolves we're ready
// to begin a new long-running-task. It's initially resolved.
let queueTail = Promise.resolve();
let queueNewTask = async genLongRunningTask => {
  await queueTail;
  await genLongRunningTask();
};

// Now setup our intervals. We don't directly generate any
// long-running-tasks here - instead we "queue" them, and
// then point the tail of the queue to their completion.
console.log('Starting...');
setInterval(() => {
  queueTail = queueNewTask(genLongRunningTask1);
}, 3000);
setInterval(() => {
  queueTail = queueNewTask(genLongRunningTask2);
}, 6000);

在我的示例中,两个间隔分别在3000ms6000ms处,因此它们应在每个6000ms上同时运行-但您会发现排队逻辑使它们保持良好且独立!在上一个任务结束之前,您将永远不会看到新任务开始。

对于您而言,您只需要编辑genLongRunningTask1genLongRunningTask2,以便它们等待并处理您的请求。类似于以下内容:

let genLongRunningTask1 = async () => {
  try {
    // Assuming `func1` returns a "response object":
    let response = await func1();
    
    /*
    Assuming the "response object" has a `json` method,
    and `display_result` is an async method for showing
    the json data.
    NOTE: this use of `await` ensures requests will remain queued
    until the previous request is done processing *and* rendering.
    To begin sending the next request after the previous request
    has returned, but overlapping with the period in which that
    request is still *rendering*, omit `async` here.
    */
    await display_result(response.json());
  } catch(err) {
    console.error('Error:', err);
  }
};

警告:请注意,排队的速度不会比完成任务的速度快!