Функции-генераторы в JavaScript
В этой статье мы объясним функции-генераторы в JavaScript.
YouTube Video
Функции-генераторы в JavaScript
Функции-генераторы в JavaScript — это особые функции, которые отличаются от обычных тем, что могут осуществлять ленивое выполнение и останавливаться и возобновлять выполнение. Поняв функции-генераторы, вы сможете эффективно работать с асинхронными операциями и последовательной обработкой больших объемов данных. Здесь мы подробно объясним, как работают функции-генераторы, как их использовать и приведем примеры практического применения.
Что такое функции-генераторы?
Функция-генератор определяется с помощью function*
(функция, определённая с использованием звёздочки) и, в отличие от обычных функций, может приостанавливать выполнение и возобновлять его, сохраняя своё состояние. Функции-генераторы обеспечивают «ленивое выполнение» и возвращают результаты поэтапно, что даёт возможность эффективно управлять памятью и обрабатывать данные последовательно.
Синтаксис
1function* generatorFunction() {
2 yield 'First value';
3 yield 'Second value';
4 return 'Done';
5}
Таким образом, функция-генератор может содержать несколько выражений yield
и использовать yield
для приостановки выполнения. Когда функция-генератор вызывается, её тело не выполняется сразу, а возвращается объект-генератор. Вы можете вызвать метод next()
для этого объекта, чтобы продолжить выполнение функции с того места, где она была остановлена.
Основы использования функций-генераторов
Теперь давайте рассмотрим простой пример использования функций-генераторов.
1function* simpleGenerator() {
2 yield 1;
3 yield 2;
4 yield 3;
5}
6
7const gen = simpleGenerator();
8
9console.log(gen.next()); // { value: 1, done: false }
10console.log(gen.next()); // { value: 2, done: false }
11console.log(gen.next()); // { value: 3, done: false }
12console.log(gen.next()); // { value: undefined, done: true }
Важно отметить, что генератор возвращает значения при каждом использовании yield
, и пока свойство done
равно false
, это означает, что возможны последующие значения. Последний вызов метода next()
возвращает done: true
, что означает завершение работы генератора.
Ключевое слово yield
и приостановка выполнения
yield
— это ключевое слово, которое указывает на точку приостановки внутри функции-генератора. Значение, расположенное справа от yield
, возвращается при вызове метода next()
. Кроме того, yield
позволяет осуществлять двустороннюю передачу данных. Другими словами, при передаче значения в качестве аргумента в метод next()
, это значение отправляется в функцию-генератор.
1function* generatorWithYield() {
2 const value1 = yield 'First yield';
3 console.log('Received value:', value1);
4 const value2 = yield 'Second yield';
5 console.log('Received value:', value2);
6}
7
8const gen = generatorWithYield();
9
10console.log(gen.next()); // { value: 'First yield', done: false }
11console.log(gen.next('Apple')); // Received value: Apple
12 // { value: 'Second yield', done: false }
13console.log(gen.next('Banana'));// Received value: Banana
14 // { value: undefined, done: true }
В этом примере вызов next('Apple')
отправляет значение 'Apple'
в функцию-генератор, где оно используется внутри функции.
Управление состоянием генератора
Генераторы могут сохранять свое состояние выполнения, что позволяет компактно представить длительные циклы или последовательную обработку данных. Следующий пример демонстрирует генератор, который бесконечно производит числа.
1function* infiniteGenerator() {
2 let i = 0;
3 while (true) {
4 yield i++;
5 if (i > 10) {
6 break;
7 }
8 }
9}
10
11const gen = infiniteGenerator();
12
13console.log(gen.next().value); // 0
14console.log(gen.next().value); // 1
15console.log(gen.next().value); // 2
16// Continues...
Этот генератор непрерывно производит числа с использованием цикла while(true)
, позволяя получать значения по мере необходимости. Это позволяет эффективно обрабатывать большие наборы данных.
Применение функций-генераторов
Функции-генераторы подходят для последовательного выполнения нескольких процессов. Например, они полезны для последовательной обработки запросов к API или разделения и обработки больших файлов.
1function* apiRequestGenerator() {
2 yield fetch('https://codesparklab.com/json/example1.json');
3 yield fetch('https://codesparklab.com/json/example2.json');
4 yield fetch('https://codesparklab.com/json/example3.json');
5}
Таким образом, генераторы, которые можно использовать для асинхронной обработки, крайне полезны для эффективного последовательного управления данными.
Асинхронные генераторы
Асинхронные генераторы, представленные в ES2018, позволяют возвращать асинхронные значения последовательно, объединяя async
и yield
. Это позволяет лаконично писать асинхронную обработку в сочетании с await
.
Синтаксис
1async function* asyncGenerator() {
2 yield await Promise.resolve(1);
3 yield await Promise.resolve(2);
4 yield await Promise.resolve(3);
5}
6
7const gen = asyncGenerator();
8
9(async () => {
10 for await (const value of gen) {
11 console.log(value); // 1, 2, 3
12 }
13})();
Асинхронные генераторы могут получать значения последовательно с использованием цикла for await...of
. Этот шаблон особенно полезен при работе с асинхронными потоками данных.
Практический пример: упрощение асинхронной обработки с помощью генераторов
Функции-генераторы также используются для упрощения потока асинхронной обработки. Например, объединяя yield
и Promise
, как показано ниже, можно писать асинхронные операции так, чтобы они выглядели синхронными.
1function* asyncFlow() {
2 const data1 = yield fetch('https://codesparklab.com/json/example1.json');
3 console.log(data1);
4 const data2 = yield fetch('https://codesparklab.com/json/example2.json');
5 console.log(data2);
6}
7
8const gen = asyncFlow();
9
10function handleAsync(generator) {
11 const next = (promise) => {
12 promise.then((result) => {
13 const { value, done } = generator.next(result);
14 if (!done) {
15 next(value);
16 }
17 });
18 };
19
20 next(generator.next().value);
21}
22
23handleAsync(gen);
Этот код последовательно делает запросы к API с использованием генератора и обрабатывает результаты.
Резюме
Функции-генераторы являются одной из мощных возможностей JavaScript, обладая способностью приостанавливать и возобновлять выполнение функции. Это позволяет осуществлять последовательную обработку, асинхронную обработку и эффективное управление большими наборами данных. Понимание генераторов — важный шаг в освоении продвинутых техник JavaScript.
Вы можете следовать этой статье, используя Visual Studio Code на нашем YouTube-канале. Пожалуйста, также посмотрите наш YouTube-канал.