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

Наивная реализация:

function* getEndlessRecords(fetchingFunction) {
  const batchSize = 20;

  // endless loop:
  for (let offset = 0; true; offset += batchSize) {
    fetchingFunction(offset, batchSize)
      .then(records => {
        for (let i=0; i < records.length; i++) {
          yield records[i]; // THIS DOESN'T WORK!!!
        }
      })
  }
}

(возможны опечатки - это упрощенный код)

Я понимаю, почему это не работает (yield работает с самой внутренней функцией), однако я не могу найти хороший способ создать генератор для асинхронных функций.

Может ли генератор потреблять вывод асинхронных функций?

1
johndodo 11 Сен 2018 в 14:56

1 ответ

Лучший ответ

Начиная с ES2018, вы могли использовать функцию асинхронного генератора :

async function* getEndlessRecords(fetchingFunction) {
  const batchSize = 20;

  // endless loop:
  for (let offset = 0; true; offset += batchSize) {
    const records = await fetchingFunction(offset, batchSize);
    for (let i=0; i < records.length; i++) {
      yield records[i];
    }
  }
}

Вы бы использовали это в функции async, используя for-await-of (не for-of):

for await (const value of getEndlessRecords(/*...*/)) {
    // Do something with `value`
}

... или просто вызвав его метод next и ожидая результата:

let g = getEndlessRecords(/*...*/);
let result;
while (!(result = await g.next()).done) {
    console.log(result.value);
}

... или, конечно, в функции, отличной от - async, вы должны использовать then в результате g.next().

До синтаксиса функции асинхронного генератора ES2018 вам пришлось бы вручную кодировать генератор, а не использовать синтаксис function*. Сделать это, возможно, - в правильно (не допуская каких-либо расширений для % GeneratorPrototype% ) довольно просто. Делать это правильно довольно неудобно, поскольку % GeneratorPrototype% не имеет общедоступного символа, и вам нужно найти его.

4
T.J. Crowder 11 Сен 2018 в 12:05