Поведение генераторов, которое мы описали в Предыдущая статья Не сложно, но это, безусловно, удивительно и может быть трудно понять в самом начале.
Таким образом, в этой статье, вместо того, чтобы вводить больше концепций, мы немного остановимся и используем только то, что мы узнали на этом моменте, обнаруживая классный вариант использования для генераторов.
Допустим, у нас есть такая функция:
function maybeAddNumbers() { const a = maybeGetNumberA(); const b = maybeGetNumberB(); return a + b; }
Функции Может быть, getnumbera
а также Может быть, getNemberb
Возвращаются номера, но иногда они также могут вернуть нулевой
или неопределенный
. Вот что “может” в их именах сигнализирует.
Когда это так, мы не должны пытаться добавлять эти значения (например, число и null
), а скорее немедленно выручить и просто возвращаться, скажем, скажем, NULL
опять таки. В конце концов, лучше вернуть NULL
Здесь, а не какое -то непредсказуемое значение, возникающее в результате добавления NULL/Undefined
с номером или с другим NULL/Undefined
Анкет
Поэтому мы должны добавить чек, который гарантирует, что эти цифры действительно определены:
function maybeAddNumbers() { const a = maybeGetNumberA(); const b = maybeGetNumberB(); if (a === null || a === undefined || b === null || b === undefined) { return null; } return a + b; }
Это работает нормально, но если A
это либо NULL
или же а неопределенное
, на самом деле нет смысла называть Может быть, getNemberb
вообще функционируют. Это потому, что мы уже знаем, что вернем NULL
в любом случае.
Итак, давайте снова переписать функцию:
function maybeAddNumbers() { const a = maybeGetNumberA(); if (a === null || a === undefined) { return null; } const b = maybeGetNumberB(); if (b === null || b === undefined) { return null; } return a + b; }
Uuuh. Из легко читаемого 3-линера это быстро выросло до 10 строк кода (не считая пустых строк). Эта функция теперь заполнена Если
Случаи, которые вы должны пройти, чтобы понять, что он делает.
И это просто игрушечный пример! Вы можете себе представить, что в реальных кодовых базах, которые содержат гораздо более сложную логику, эти проверки станут еще более сложными.
Так что, если бы мы могли использовать генераторы здесь и вернуть код в его более простой форме?
Взгляните на это:
function* maybeAddNumbers() { const a = yield maybeGetNumberA(); const b = yield maybeGetNumberB(); return a + b; }
Что если бы мы могли дать это доход
Выражение функциональности проверки, если
это фактическое значение, а не NULL
или неопределенный
?
Если выяснилось, что
это нулевой
или неопределенный
, мы бы просто пошли рано и вернулись нулевой
, точно так же, как в более многословной версии нашего кода.
Таким образом, мы могли бы написать код, который выглядит почти Как будто это имеет дело только с фактическими, определенными значениями. Это сам генератор, который бы проверил бы вас, если это действительно так, и он будет действовать соответственно! Звучит волшебно, не так ли?
И все же это не только возможно, но и очень легко написать!
Конечно, сами генераторы не обладают этой функциональностью. Они просто возвращают итераторы и, необязательно, позволяют вам вводить некоторые значения обратно в генератор.
Итак, нам придется написать обертку – давайте назовем это Runmaybe
– который даст генератору эту возможность.
Поэтому вместо того, чтобы напрямую вызывать функцию:
const result = maybeAddNumbers();
Мы будем называть это аргументом для этой обертки:
const result = runMaybe(maybeAddNumbers());
Это шаблон, который вы увидите невероятно часто с генераторами.
Генераторы сами по себе мало что делают, но, написав такие пользовательские обертки, как этот, вы можете предоставить генераторы пользовательские поведения! И это именно то, что мы будем делать прямо сейчас.
Так Runmaybe
Очевидно, это функция, и она принимает один аргумент – итератор, созданный генератором:
function runMaybe(iterator) { }
Мы запустим этот итератор в В то время как
петля. Чтобы сделать это, нам нужно впервые позвонить в итератор и начать проверять его Готово
имущество:
function runMaybe(iterator) { let result = iterator.next(); while(!result.done) { } }
Теперь в петле у нас есть два варианта. Если Результат
это нулевой
или неопределенный
Мы хотим немедленно нарушить процесс итерации и вернуть NULL
Анкет Давайте сделаем это:
function runMaybe(iterator) { let result = iterator.next(); while(!result.done) { if (result.value === null || result.value === undefined) { return null; } } }
Вы можете видеть, что мы сразу же останавливаем итерацию с возврат
И мы возвращаем NULL
от нашей обертки.
Если однако Результат
это фактическое, определенное значение, мы хотим «вернуть» генератор.
Например, в Доход может быть GetgeNumbera ()
, если окажется, что Может быть, getnumbera ()
на самом деле число, мы просто хотим заменить Доход может быть GetgeNumbera ()
со значением самого числа.
Еще более конкретно, если Может быть, getnumbera ()
Оценивается, скажем, номер 5, мы хотели бы изменить const, может быть, GetgeNumbera ();
в Конст;
Анкет Как вы можете видеть, мы не хотим каким -либо образом менять утетую, а просто передавать его назад к генератору.
Мы помним, что можем заменить доход
с некоторым значением, передавая это значение в качестве аргумента итераторам Следующий
метод Итак, давайте сделаем это!
function runMaybe(iterator) { let result = iterator.next(); while(!result.done) { if (result.value === null || result.value === undefined) { return null; } // we are passing result.value back // to the generator result = iterator.next(result.value) } }
И, как вы можете видеть, новый результат теперь хранится в результат
переменная снова. Мы специально объявлены результат
с пусть
так что это возможно.
Мы почти там – если в любой момент наш генератор встречается с нулевой/неопределенный
При отдаче значения мы просто возвращаем NULL
от нашего Runmaybe
обертка.
Но нам нужно что -то вернуть также, если процесс итерации заканчивается, не встречая ни одного NULL/Undefined
ценности. В конце концов, если мы получим два фактических числа в нашем генераторе, мы хотим вернуть их сумму из обертки!
Наш Maybeaddnumbers
Генератор заканчивается возврат
утверждение.
Мы помним, что вернуть
В генераторе заставляет его итератор возвращать объект {value:
Из Следующий
вызов.
Когда это происходит, В то время как
петля перестанет работать, потому что Готово
свойство будет установлено на истинный
. Но это последнее возвратное значение (в нашем конкретном случае a + b
value) все еще будет храниться в Результат
имущество! Так что в конце мы можем просто вернуть его:
function runMaybe(iterator) { let result = iterator.next(); while(!result.done) { if (result.value === null || result.value === undefined) { return null; } result = iterator.next(result.value) } // just return the last value // after the iterator is done return result.value; }
Вот и все!
Давайте создадим манекен Может быть, getnumbera
и Может быть, getNemberb
функции. Давайте сначала вернем их фактические цифры:
const maybeGetNumberA = () => 5; const maybeGetNumberB = () => 10;
Если мы запустим наш код сейчас и зарегистрируем результаты:
function* maybeAddNumbers() { const a = yield maybeGetNumberA(); const b = yield maybeGetNumberB(); return a + b; } const result = runMaybe(maybeAddNumbers()); console.log(result);
Посмотрим – как и ожидалось – номер 15 в консоли.
Однако давайте изменим одно из добавленных чисел на NULL
:
const maybeGetNumberA = () => null; const maybeGetNumberB = () => 10;
Теперь запуск журналов кода NULL
!
Однако для нас было важно убедиться, что Может быть, getNemberb
Функция не вызывала, когда первая функция – Может быть, getnumbera
– Возвращает NULL/Undefined
Анкет Итак, давайте дважды проверим, если мы действительно преуспели.
Мы можем сделать это, просто добавив Консоль.log
ко второй функции:
const maybeGetNumberA = () => null; const maybeGetNumberB = () => { console.log('B'); return 10; }
Если мы написали наш Runmaybe
Помощник правильно, буква B
должен не появляются в консоли при запуске этого примера.
И действительно, если вы запустите код сейчас, вы просто увидите NULL
в консоли и ничего больше. Это означает, что наш помощник фактически перестает запускать генератор после того, как он столкнется с NULL/Undefined
ценность.
Наш код также работает так, как задумано – журналом нулевой
– В любой из этих комбинаций:
const maybeGetNumberA = () => undefined; const maybeGetNumberB = () => 10;
const maybeGetNumberA = () => 5; const maybeGetNumberB = () => null;
const maybeGetNumberA = () => undefined; const maybeGetNumberB = () => null;
и т.п.
Мощность этого примера не лежит при запуске этого конкретного кода.
Это заложено в том, что мы создали Общий помощник, который может справиться любой Генератор, который потенциально дает NULL/Undefined
ценности.
Например, если мы написали более сложную функцию:
function* maybeAddFiveNumbers() { const a = yield maybeGetNumberA(); const b = yield maybeGetNumberB(); const c = yield maybeGetNumberC(); const d = yield maybeGetNumberD(); const e = yield maybeGetNumberE(); return a + b + c + d + e; }
Мы можем запустить это в нашем Runmaybe
Обертка тоже без проблем!
На самом деле, наша обертка даже не полагается на тот факт, что в наших примерах эти функции возвращают числа. Обратите внимание, что в Ранмайб
Мы вообще не упоминаем тип числа. Так что независимо от того, какие значения вы используете в своем генераторе – числа, строки, объекты, массивы, более сложные структуры данных – они все равно будут работать с нашим помощником!
Это именно то, что разработчики находят захватывающим в генераторах. Они позволяют вам внедрять пользовательские функциональные возможности в код, который выглядит очень регулярно (кроме тех, что вы, конечно, вызовы Вам просто нужно создать обертку, которая итерации над генератором особым образом. Таким образом, обертка в основном «предоставляет» функциональность генератора!
И эта функциональность может быть буквально всем, что вы хотите. Генераторы вводят потенциально бесконечные возможности, и единственное ограничение – это наше воображение!
И в следующих статьях мы будем продолжать изучать эти возможности, особенно в сочетании с React. Так что, если это звучит интересно для вас, следуйте за мной Twitter не пропустить эти будущие статьи.
Спасибо за чтение!
Оригинал: “https://dev.to/mpodlasin/generators-in-javascript-part-ii-simple-use-case-g6f”