Рубрики
Без рубрики

Генераторы в JavaScript, часть II – простой вариант использования

Поведение генераторов, которое мы описали в предыдущей статье, не сложно, но это … Tagged with JavaScript, Codenewbie, учебник.

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

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

Допустим, у нас есть такая функция:

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: , Dode: true} Из Следующий вызов.

Когда это происходит, В то время как петля перестанет работать, потому что Готово свойство будет установлено на истинный . Но это последнее возвратное значение (в нашем конкретном случае 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”