Превращение обратного вызова, который вызывается несколько раз в функцию генератора - PullRequest
2 голосов
/ 11 марта 2019

У меня есть функция, которая асинхронно выбирает строки базы данных и вызывает функцию обратного вызова для каждой строки.Я пытаюсь написать обертку, которая является функцией генератора, которая возвращает каждый раз, когда возвращается строка, но я не вижу, как правильно получить.

Исходный код выглядит примерно так:

db.each(query, (err, row) => {
  // do something here with row
}, () => {
  // called after the last row is returned
})

Я знаком с тем, как работает генератор, но выход, похоже, принадлежит самой функции генератора, а не анонимной функции.Поэтому я думаю, что что-то вроде этого не будет работать:

function* dbEach(db, query) {
    db.each(query, (err, row) => {
      yield row
    })
}

Когда я на самом деле пытаюсь , это выдает ошибку "Неожиданный идентификатор".

Я посмотрел немногодалее, и кажется, что ES2018 теперь имеет асинхронные итераторы, которые должны сделать это возможнымОднако у меня возникают проблемы, когда я не могу понять, как именно я могу использовать асинхронные итераторы в случае, когда у меня уже есть обратный вызов, который вызывается несколько раз.

1 Ответ

3 голосов
/ 11 марта 2019

Вы можете сделать генератор async, затем await Обещание, которое разрешается со всеми строками (так что у вас есть ссылка на переменную rows на верхнем уровне dbEach), а затем вы можете получить каждая строка в этом массиве rows:

async function* dbEach(db, query) {
  const rows = await new Promise((resolve, reject) => {
    const rows = [];
    db.each(query, (err, row) => {
      if (err) reject(err);
      else rows.push(row);
    }, () => resolve(rows));
  });
  for (const row of rows) {
    yield row;
  }
}

Использовать с:

for await (const row of dbEach(...)) {
  // do something
}

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

async function* dbEach(db, query) {
  const rows = await new Promise((resolve, reject) => {
    db.getAllRows(query, (err, rows) => {
      if (err) reject(err);
      else resolve(rows);
    });
  });
  for (const row of rows) {
    yield row;
  }
}

Хотя я не думаю, что генератор здесь очень помогает - вы также можете просто await Обещание, которое разрешает строки и выполняет итерацию по строкам синхронно:

function getRows(db, query) {
  return new Promise((resolve, reject) => {
    db.getAllRows(query, (err, rows) => {
      if (err) reject(err);
      else resolve(rows);
    });
  });
}

const rows = await getRows(...);
for (const row of rows) {
  // ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...