Урожай! Урожай! Как работают генераторы в JavaScript.

Перейти к профилю Ашай Мандвария 🖋️🍕

Ашай Мандвария 🖋️🍕ЗаблокированоUnblockFollowFollowing

4 фев


фото Фредерик Троваттен.com на Скрыть

Если заголовок еще не дает подсказки, мы будем обсуждать генераторы в этой части.

Прежде чем перейти к генераторам, давайте повторим некоторые основы функций.

  • В JavaScript функции представляют собой набор операторов, которые выполняют задачу и возвращают некоторое значение, завершающее функцию.
  • Если вы вызываете функцию снова и снова, она будет выполнять все операторы снова и снова.
  • Стрелы, вылетевшие из лука, уже нельзя остановить — они либо попадают, либо промахиваются. Точно так же однажды вызванная функция не может быть остановлена, она запустится, вернет значение, выдаст ошибку, а затем остановится после выполнения всех операторов.

Нам нужно только помнить эти 3 момента, чтобы понять генераторы.

Генераторы

Генератор — это особый тип функции, которая может остановить свое выполнение на полпути, а затем запуститься с той же точки через некоторое время. Генераторы представляют собой комбинацию функций и итераторов. Это немного запутанное утверждение, но я позабочусь о том, чтобы к концу статьи эта линия была ясна.

Для наглядности представьте, что вы играете в игру, и вдруг мама звонит по какой-то работе. Вы ставите игру на паузу, помогаете ей, затем возобновляете игру снова. То же самое и с генераторами.

Ан итератор это объект, который определяет последовательность и, возможно, возвращаемое значение после ее завершения. — МДН.

Итераторы сами по себе — огромная тема, и они не являются целью этой статьи.

Базовый синтаксис

Генераторы определяются как функция со звездочкой

function* name(arguments) {
   statements
}

рядом с функцией.

**name — ** Имя функции.

**arguments — ** Аргументы функции.

**операторы — ** Тело функции.

ВозвращатьсяФункция может возвращать практически все, начиная от значения, объекта или самой функции. Функция-генератор возвращает специальный объект, называемый объектом-генератором (не совсем верно

{ value: value, done: true|false}

). Объект выглядит как фрагмент ниже valueОбъект имеет два свойства done а также . Значение содержит значение, которое должно быть уступил. Готово состоит из Логическое значение (истина|ложь) который сообщает генератору, если .следующий() даст значение или

неопределенный.

function* generator(e) { yield e + 10; yield e + 25; yield e + 33;}var generate = generator(27);

console.log(generate.next().value); // 37console.log(generate.next().value); // 52console.log(generate.next().value); // 60console.log(generate.next().value); // undefined

Приведенное выше утверждение будет трудно переварить. Давайте изменим это на примере.

Давайте разберемся с механикой приведенного выше кода построчно. строки 1–5:

Строки 1–5 определяют генератор с таким же именем и аргументом e. Внутри тела функции она содержит кучу операторов с ключевым словом yield и после этого выполняется какая-то операция. строка 6:

В строке 6 генератор присваивается переменной с именем generate. строки 8–11: console.log Эти строки вызывают кучу nextкаждый из которых вызывает генератор, привязанный к value метод, который требует

свойство объекта-генератора.Всякий раз, когда вызывается функция генератора, в отличие от обычных функций, она не начинает выполнение сразу. Вместо этого возвращается итератор (фактическая причина * используется генератором. Он сообщает JS, что должен быть возвращен объект итератора. next()). Когда yieldвызывается метод итератора, запускается выполнение генератора и выполняется до тех пор, пока не будет найден первый next() утверждение. В этой точке выхода возвращается объект генератора, характеристики которого уже объяснены. Вызов yieldфункция снова возобновит функцию генератора, пока не найдет другую yieldsоператор, и цикл возвращается до тех пор, пока все

исчерпаны. nextПосле этого момента, если

вызывается, он возвращает объект генератора со значением undefined.

Теперь давайте попробуем получить другую функцию-генератор из исходного генератора, а также оператор return. return А done propertyоператор в генераторе заставит генератор завершить свое выполнение, как и любая другая функция. trueобъекта-генератора будет установлено значение valueи valueвозвращенный будет установлен в yieldsсвойство объекта-генератора. Все остальные undefinedвернется

.

Если выдается ошибка, то также останавливается выполнение генератора, что дает сам генератор. yieldingЗа yieldгенератор нам нужно указать * против yield* чтобы сообщить JS, что генератор получен. yieldделегирует другой функции-генератору — по этой причине мы можем generator2все значения generate.next() функция с помощью yielded исходной генераторной функции. Первое значение yieldedиз первой функции генератора и двух последних yieldedзначения генерируются функцией генератора, но

от оригинального генератора.

Преимущества

Ленивая загрузка

Ленивая загрузка по сути является оценкой значения только тогда, когда в этом есть необходимость. Как мы увидим в следующем примере, мы действительно можем сделать это с помощью генераторов. Мы можем выдавать значения только тогда, когда это необходимо, а не все одновременно.next() Приведенный ниже пример взят из другого примера в этой статье и генерирует бесконечные случайные числа. Здесь мы видим, что можем вызывать столько

function * randomize() {
  while (true) {
let random = Math.floor(Math.random()*1000);
    yield random;
  }
}

var random= randomize();

console.log(random.next().value)

как мы хотим, и не получаем все значения, которые он производит. Только нужные.

Эффективная память

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

Подводные камни

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

Генераторы не позволяют повторять значения снова и снова. Как только все значения исчерпаны, мы должны создать новый экземпляр генератора, чтобы снова перебрать все значения.

Зачем нужны Генераторы?

Генераторы обеспечивают широкий спектр применений в JavaScript. Давайте попробуем воссоздать некоторые из них сами.

Реализация итераторов Итератор

это объект, который позволяет программисту перемещаться по контейнеру — Википедия

Мы будем печатать все слова, присутствующие в строке, с помощью итераторов. Строки тоже являются итераторами.

const string = 'abcde';
const iterator = string[Symbol.iterator]();
console.log(iterator.next().value)
console.log(iterator.next().value)
console.log(iterator.next().value)
console.log(iterator.next().value)
console.log(iterator.next().value)

Итераторы

function * iterator() {
yield 'a';
yield 'b';
yield 'c';
yield 'd';
yield 'e';
}
for (let x of iterator()) {
console.log(x);
}

Вот то же самое с генераторами

  • Сравнивая оба метода, легко увидеть, что с помощью генераторов мы можем сделать это с меньшим количеством помех. Я знаю, что это не очень хороший пример, но достаточно, чтобы доказать следующие моменты: next()
  • Нет реализации [Symbol.iterator]() Нет
  • призыв object.done В некоторых случаях нам даже нужно установить

свойство возвращает значение true/false с помощью итераторов.

Async-Await ~ Промисы+Генераторы Вы можете прочитать мойпредыдущий статья об Async/Await, если вы хотите узнать о них, и проверить это

для обещаний.

Грубо говоря, Async/Await — это просто реализация генераторов, используемых с промисами.

async function async-await(){
let a=await(task1);
console.log(a);

let b=await(task2);
console.log(b);

let c=await(task3);
console.log(c);

}

Асинхронное ожидание

function * generator-promise()
{
let a=yield Promise1();
console.log(a);
let b=yield Promise1();
console.log(b);
let c=yield Promise1();
console.log(c);

}

Промисы+Генераторы

Как мы видим, оба дают одинаковый результат и почти одинаковым образом. Это потому, что механизм Async/Await основан на комбинации генераторов и обещаний. В Async/Await гораздо больше, чем показано выше, но мы можем рассмотреть это только для демонстрации использования генератора.

Бесконечная структура данных

function * randomize() {
  while (true) {
let random = Math.floor(Math.random()*1000);
    yield random;
  }}
var random= randomize();
while(true)
console.log(random.next().value)

Заголовок может ввести в заблуждение, но это правда. Мы можем создавать генераторы с использованием цикла while, который никогда не закончится и всегда будет возвращать значение. next()В приведенном выше фрагменте мы создаем бесконечный генератор, который будет выдавать случайное число при каждом

призыв. Его можно назвать бесконечным потоком случайных чисел. Это очень простой пример.

Вывод

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

Следуйте за мной и аплодируйте!

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *