Асинхронные генераторы
Асинхронные итераторы открывают нам путь к созданию асинхронных генераторов. Асинхронные генераторы позволяют нам использовать оператор await
и получать и возвращать данные асинхронным образом.
Для определения асинхронного генератора перед функцией генератора ставится оператор async
:
async function* название_функции_генератора(){
yield возвращаемое_значение;
}
Рассмотрим простейший генератор:
async function* generatePersonAsync(){
yield "Tom";
}
Здесь определен асинхронный генератор generatePersonAsync, в котором возвращается одно значение - строка Tom
.
Особенностью асинхронного генератора является то, что при обращении к его методу next()
возвращается объект Promise
. А полученный объект Promise
, в свою очередь возвращает объект с двумя свойствами { value, done }
, где value
собственно хранит возвращаемое значение, а done
указывает доступны ли в генераторе еще данные.
Например, возьмем выше определенный асинхронный генератор:
async function* generatePersonAsync(){
yield "Tom";
}
const personGenerator = generatePersonAsync();
personGenerator.next(); // Promise
Здесь с помощью метода next()
получаем промис. Далее через метод then()
мы можем получить из промиса объект:
const personGenerator = generatePersonAsync();
personGenerator.next()
.then(data => console.log(data)); // {value: "Tom", done: false}
При обращении к свойству value
полученного из промиса получить сами данные:
const personGenerator = generatePersonAsync();
personGenerator.next()
.then(data => console.log(data.value)); // Tom
С помощью оператора await
из метода next()
генератора мы можем получить данные:
async function* generatePersonAsync() {
yield "Tom";
yield "Sam";
yield "Bob";
}
async function printPeopleAsync() {
const personGenerator = generatePersonAsync();
while (!(person = await personGenerator.next()).done) {
console.log(person.value);
}
}
printPeopleAsync();
Консольный вывод:
Tom
Sam
Bob
Поскольку асинхронный генератор представляет асинхронный итератор, то данные генератора также можно получить через цикл for-await-of
:
async function* generatePersonAsync() {
yield "Tom";
yield "Sam";
yield "Bob";
}
async function printPeopleAsync() {
const personGenerator = generatePersonAsync();
for await (person of personGenerator) {
console.log(person);
}
}
printPeopleAsync();
// Tom
// Sam
// Bob
await в асинхронных генераторах
Главным преимуществом асинхронным генераторов является то, что мы можем использовать в них оператор await
и соответственно получать данные из источников данных, которые используют асинхронный API:
async function* generatePersonAsync(people) {
for (const person of people) yield await new Promise((resolve) => setTimeout(() => resolve(person), 2000));
}
async function printPeopleAsync(people) {
for await (const item of generatePersonAsync(people)) {
console.log(item);
}
}
printPeopleAsync(["Tom", "Sam", "Bob"]);
Здесь для имитации получения данных из асинхронного источника данных применяется промис, который через 2000 секуд возвращает один из элементов массива, который передается в функцию генератора:
yield await new Promise(resolve => setTimeout(() => resolve(person), 2000));