асинхронное ожидание с несколькими setIntervals - PullRequest
0 голосов
/ 10 июня 2019

У меня есть два запроса API, один из которых вызывается каждые 5000 мс, а другой - каждые 30000 мс. Я хочу убедиться, что каждый вызов завершен, прежде чем отправлять новый запрос на сервер. Я не хочу, чтобы какие-либо запросы перекрывали друг друга. Например, если API func1 еще не завершено, я не хочу выполнять вызов API 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.

function func1() {
        return setInterval(() => fetch(url, { method: 'GET' }), 5000);
}

function func2() {
        return setInterval(() => fetch(url, { method: 'GET' }), 30000);
}

Я ожидал бы, что это сначала запустит func1 (), подождет, пока он разрешится, а затем запустит func2 (). Вместо этого func1 () вызывается дважды и никогда не попадает в func2 (). Должны ли setIntervals быть установлены внутри функции vals ()? Любое руководство, чтобы сделать эту работу будет высоко ценится.

1 Ответ

1 голос
/ 10 июня 2019

Хорошо, это немного сложно! У вас есть два разных интервала порождения задач (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);

В моем примере два интервала имеют значения 3000ms и 6000ms, поэтому они должны запускаться одновременно каждый 6000ms - но вы увидите, что логика очередей сохраняет их красивыми и отдельными! Вы никогда не увидите запуск новой задачи до ее завершения.

В вашем случае вам нужно только отредактировать genLongRunningTask1 и genLongRunningTask2, чтобы они ожидали и обрабатывали ваш запрос. Примерно так:

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);
  }
};

Предупреждение: будьте осторожны, чтобы не ставить задачи в очередь быстрее, чем задачи могут быть выполнены!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...