JavaScriptの発電機パート2 -簡単なユースケース


で説明したジェネレータの動作previous article 複雑ではないが、それは確かに驚くべきであり、非常に最初に把握するのは難しいかもしれない.
したがって、この記事では、より多くの概念を導入する代わりに、私たちは少し休止して、発電機のために涼しい使用ケースを発見している間、我々がこの点について学んだものだけを使います.
次のような機能があるとしましょう.
function maybeAddNumbers() {
    const a = maybeGetNumberA();
    const b = maybeGetNumberB();

    return a + b;
}
関数maybeGetNumberA and maybeGetNumberB 返り値null or undefined . それは、彼らの名前の「多分」が意味するものです.
その場合、それらの値を追加しようとしてはいけません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 またはundefined , 本当に電話をかける点はないmaybeGetNumberB すべての関数.それは、我々がすでにAを返すということを知っているからです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;
}
ユウ読みやすい3ライナーから、これはすぐにコードの10行(空の行をカウントしない)に成長した.この関数はif ケース、あなたはそれが何を理解するために通過する必要があります.
そしてこれは単なるおもちゃの例です!より複雑なロジックを含む実際のコードベースでは、それらのチェックはさらに複雑になるでしょう.
それで、ここでジェネレータを使用して、より単純な形にコードを戻すことができるならば、どうですか?
以下を見てください.
function* maybeAddNumbers() {
    const a = yield maybeGetNumberA();
    const b = yield maybeGetNumberB();

    return a + b;
}
私たちがそれを与えることができるならばyield <something> 式のチェック機能<something> は実際の値ではなくnull or undefined ?
それがわかるならば<something> is null or undefined , 我々は、ちょうど早く保釈して、帰りますnull , 正確に我々のコードのより詳細なバージョンのように.
このようにして、実際に定義された値だけを扱うようなコードを書くことができました.
それは本当にそれがそうであるならば、それはあなたのためにチェックするジェネレータ自体です、そして、それはそれに応じて行動します!魔法だね.
しかし、それだけでなく、非常に書くことも可能です!
もちろん、ジェネレータ自体はこの機能を持っていません.これらはイテレータを返し、オプションでいくつかの値をジェネレータに戻すことができます.
それで、我々はラッパーを書かなければなりませんrunMaybe - これはジェネレータにこの機能を与えます.
関数を直接呼び出す代わりに:
const result = maybeAddNumbers();
このラッパに対する引数として呼び出します.
const result = runMaybe(maybeAddNumbers());
これは非常に頻繁にジェネレータで表示されるパターンです.
ジェネレータ自体はあまりしないが、このようなカスタムラッパーを書くことにより、ジェネレータのカスタム動作を付与することができます!そして、それはまさに我々が今することです.
So runMaybe 明らかに関数であり、1つの引数を受け付けます-ジェネレータによって生成されたイテレータ
function runMaybe(iterator) {

}
このイテレータを実行しますwhile ループ.そのためには、イテレータを初めて呼び出す必要がありますdone プロパティー
function runMaybe(iterator) {
    let result = iterator.next();

    while(!result.done) {

    }
}
ループ内で2つのオプションがあります.If result.value is null or undefined 繰り返し処理を中断して戻ります.null . そうしましょう
function runMaybe(iterator) {
    let result = iterator.next();

    while(!result.done) {
        if (result.value === null || result.value === undefined) {
            return null;
        }
    }
}
あなたはすぐに我々はすぐに反復を停止していることがわかりますreturn そして、我々はnull 我々のラッパーから.
でもresult.value 実際の、定義された値です、我々は発電機に「それを返します」.
例えば、yield maybeGetNumberA() , それがわかるならばmaybeGetNumberA() 実際には、私たちはyield maybeGetNumberA() を返します.
より具体的にはmaybeGetNumberA() 番号5に評価し、変更したいconst a = yield maybeGetNumberA(); into const a = 5; . ご覧のように、私たちはどんな値でも値を変更したくないが、単に発電機に戻します.
我々は置き換えることができることを覚えてyield <something> を返します.next メソッド.そうしましょう!
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)
    }
}
そして、あなたが見ることができるように、新しい結果は現在result 再び変数.特に宣言しましたresult with let それで、それは可能です.
我々はほとんどそこにある-任意の時点で我々の発電機が発生した場合null/undefined 値をyieldするとき、私たちはnull 我々からrunMaybe ラッパー.
しかし、繰り返し処理が終了しなければ何かを返す必要があるnull/undefined 値.結局、我々が我々の発電機で2つの実数を受け取るならば、我々はラッパーから彼らの合計を返したいです!
我々maybeAddNumbers 発電機はreturn 文.
私たちはreturn <something> ジェネレータで、イテレータがオブジェクトを返す原因となります{ value: <something>, done: true } からnext コール.
これが起こるとwhile ループは実行を停止しますdone プロパティはtrue . しかし、その最後の値はa + b 値はまだresult.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;
}
そしてそれだ!
ダミーを作ろうmaybeGetNumberA and maybeGetNumberB 関数.最初に実数を返しましょう
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番です.
しかし、追加された数字の1つを変更しましょうnull :
const maybeGetNumberA = () => null;
const maybeGetNumberB = () => 10;
コードログの実行null !
しかし、それを確かめることは我々にとって重要でしたmaybeGetNumberB 関数は最初の関数のときに呼び出されません.maybeGetNumberA - リターンnull/undefined . それで、我々が本当に成功するならば、チェックしてください.
我々は、単にAを加えることによってそれをすることができますconsole.log 2番目の関数
const maybeGetNumberA = () => null;
const maybeGetNumberB = () => {
    console.log('B');
    return 10;
}
我々が書くならばrunMaybe 正しく、ヘルパー、手紙B この例を実行するとコンソールに表示されません.
そして、実際には、コードを実行する場合は、単に表示されますnull コンソールでは、何も他の.これは、私たちのヘルパーが実際に発生した後にジェネレータを実行停止しますnull/undefined 値.
我々のコードはまた、意図通りに動作しますnull - いずれの組み合わせにおいても
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 ラッパーも任意の問題なし!
実際、我々のラッパーは、我々の例において、それらの機能が数を返すという事実に頼りません.注意runMaybe 我々は、すべての数型については言及しません.だから、あなたのジェネレータで使用されている値の種類は-番号、文字列、オブジェクト、配列、より複雑なデータ構造-それはまだ我々のヘルパーで動作します!
これは、開発者が発電機についてエキサイティングなものを見つけるものです.それらは非常に規則的に見えるコードにカスタム機能を導入することができますyield もちろんコールする).特定の方法でジェネレータを繰り返すラッパーを作成する必要があります.このように、ラッパーは基本的に“ジェネレータ”カスタム機能を補助する!
そして、その機能は文字通り何かをすることができます.発電機は潜在的に無限の可能性を導入し、唯一の制限は我々の想像力です!
そして、次の記事では、特に反応と組み合わせて、それらの可能性を探求し続けるでしょう.だから、これはあなたに興味深い音、それらの将来の記事をお見逃しなく私に従ってください.
読書ありがとう!