Генерация набора данных с обещаниями

1

В настоящее время я пытаюсь создать массив пар с асинхронными вызовами в javascript, но я просто не могу получить его в правильном порядке.

generateDataPoints: function (iterable, source, arg) {
  let pairs = []
  let prevTime = 0
  for (let index in iterable) {
    let event = iterable[index]
    getTime(event.valueOf()).then(function (time) {
      query(source[arg], event.valueOf()).then(function(val) {
        if (time !== prevTime) {
          prevTime = time
          pairs.push([time, val])
          console.log(pairs) // This works as expected but only happens after the program returns
        } else {
          Promise.resolve()
        }
      })
    })
  }
  return Promise.resolve(pairs)
}

Проблема в том, что команда "pairs.push.." происходит после того, как я вернусь. Я не могу понять, что именно происходит, и как я могу синхронизировать этот процесс. Любая помощь приветствуется.

  • 0
    так что ... ну, вы, конечно, ввели обещание в свой код, но ничего, что вы с ним сделали, не приведет к возвращению обещания, которое не разрешится, пока работа не будет завершена.
  • 0
    @KevinB Хм, я попытался обернуть цикл for в новое обещание, возвращая при этом «resol (пары)». Это тоже не сработало
Показать ещё 1 комментарий
Теги:
callback
bluebird

1 ответ

0

Вы смешиваете синхронный код (например, цикл for) с асинхронным кодом. Попробуйте что-то вроде этого:

function generateDataPoints(iterable, source, arg) {
  let prevTime = 0
  [...iterable].reduce((promiseChain, event) => {
    let pairs;
    return promiseChain
      .then(p => {
        pairs = p;
        return Promise.all([
          getTime(event.valueOf()),
          query(source[arg], event.valueOf())
        ])
      })
      .then(([time, val]) => {
        if (time !== prevTime) {
          prevTime = time
          return pairs.concat([[time, val]]);
        } else {
          return pairs;
        }
      });
    })
  }, Promise.resolve([]));
}

Это уменьшает iterable до последовательной цепочки Promise, которая в конечном итоге будет содержать все пары.

Если ваша среда позволяет это, вы также можете преобразовать свою функцию с небольшими изменениями в функцию async:

generateDataPoints: async function (iterable, source, arg) {
  let pairs = []
  let prevTime = 0
  for (let index in iterable) {
    let event = iterable[index]
    const [time, val] = await Promise.all([
      getTime(event.valueOf()),
      query(source[arg], event.valueOf())
    ]);
    if (time !== prevTime) {
      prevTime = time
      pairs.push([time, val])
    }
  }
  return pairs;
}

Изменить:

При ближайшем рассмотрении не похоже, что вам нужно секвестировать эти обещания. Вместо этого вы можете запускать их параллельно:

function generateDataPoints(iterable, source, arg) {
  Promise.all(
    [...iterable].map(event => Promise.all([
      getTime(event.valueOf()),
      query(source[arg], event.valueOf())
    ])
  ).then(pairs => {
    let prevTime = 0
    return pairs.filter(([time, val]) => {
      if (time !== prevTime) {
        prevTime = time;
        return true;
      } else {
        return false;
      } 
    });
  });
}
  • 0
    Вы также используете Bluebird в соответствии с вашими тегами. Это означает, что у вас есть вкусности, такие как Promise.map которые делают вещи еще проще.
  • 0
    Итак, в настоящее время я реализовал третье, что вы написали, и вот проблема. У меня есть generateDataPoints, вызываемые где-то еще, давайте вызовем функцию x. X получает список пар после сопоставления, однако процесс фильтрации еще не начался. Почему это?
Показать ещё 6 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню