JavaScript Generatorsガイド
6739 ワード
最近、Redux Sagasの仕事原理をよりよく理解するために、JavaScript generatorsの知識を学びました.インターネットから集めたさまざまな知識点を一つの文章に凝縮しました.この文章は分かりやすく、厳格で、初心者のgeneratorsとしてマニュアルを使用できるようになりたいです.
概要
JavaScriptはES 6にジェネレータを導入した.ジェネレータ関数は、それらを一時停止および回復できる点を除いて、従来の関数と同様である.生成器も、サブジェネレータと密接に関係しています.生成器オブジェクトは、サブジェネレータです.JavaScriptでは、関数の呼び出し後は通常一時停止や停止ができません.(はい、非同期関数はawait文を待っている間は一時停止しますが、非同期関数はES 7の時に導入されます.また、非同期関数はジェネレータの上に構築されています.)一つの一般関数は、エラーが戻ったり投げ出されたりした時にのみ終了します.
ジェネレータとサブジェネレータ
MDNから来ました:
JavaScriptでは、ディケンサはオブジェクトであり、シーケンスを定義し、終了時には戻り値を返します.より具体的には、シーケンサは、next()方法を使用してIteratocolを実現する任意のオブジェクトであり、この方法は、2つの属性を有するオブジェクトを返す.これはシーケンス内のnext値である.とdoneは、シーケンスの最後の値に反復した場合、trueです.もしvalueとdoneが一緒に存在するならば、それはディズエバの戻り値です.
そのため、ディエテンダーの本質は:シーケンスを定義するオブジェクト には は、2つの属性を持つオブジェクトを返します.
ジェネレータを作成しますか?いいえ.実際には、私たちはすでに閉包pre-ES 6を使用して、フィボナッチの無限数列を作成することができます.
カスタムディケンサは有用なツールですが、それらの内部状態を明示的に維持する必要があるので、それらを作成するには注意深くプログラミングする必要があります.ジェネレータ関数は、反復アルゴリズムを定義する連続ではない関数を作成することによって、強力な代替法を提供する.
言い換えれば、エラーの可能性がより小さいことを意味する、ジェネレータを使用して、より簡単に(パケットを閉じる必要がない!)を作成します.
ジェネレータとサブジェネレータとの関係は、ジェネレータ関数が返したジェネレータオブジェクトがサブジェネレータです.
構文
ジェネレータ関数は、function*文法を使って作成し、yieldキーを使って一時停止します.最初にジェネレータ関数を呼び出してもコードは実行されません.反対に、生成器オブジェクトを返します.この値は、ジェネレータのnext()メソッドを呼び出すことによって使用され、この方法は、yieldキーワードに出会うまでコードを実行し、その後、next()を再度呼び出すまで停止する.
yield一時停止実行
上のコードの断片にはいくつかの特殊な点があることに気づくかもしれません.2番目のnext()呼び出しは、done:trueではなく、done:falseのオブジェクトを生成します.私たちはジェネレータ関数で最後の文を実行していますが、done属性はtrueではないですか?わけではない.yield文に出会うと、その後ろの値(この例では「World」)が生成され、実行が一時停止されます.したがって、第二のnext()呼び出しは第二のyield文で一時停止されていますので、実行はまだ完了していません.第二のyield文の後に再起動を実行した場合のみ、実行は完了します.コードは再実行されません.next()を呼び出して、次のyield文(存在すると仮定して)プログラムに実行して、値を生成して、一時停止することができます.プログラムは実行を再開する前に、yield文の後には何の内容もなく、もう一つのnext()呼び出しで実行されます.
yieldとreturn
上記の例では、yieldを使用して、値を生成器の外部に渡す.私達もreturnを使ってもいいです.しかし、returnを使って実行を終了し、done:trueを設定することができます.
yield:nextメソッドのパラメータ
私たちはこれまで、yield伝送生成器の外部の値を使っています.しかし、yieldは実際には双方向であり、値を生成器関数に伝達させることができる. 最初のnext()呼び出し時に、yield'Hello world'に出会うまでずっと動作します.この基礎の上で{value:'Hello world',done:false}と一時停止を生成します.そういうことです.皆さんがご覧のように、最初のnext()に送る呼び出しのいかなる値も使用されません. 再度next(...)を呼び出すと、実行は再開されます.この場合、実行には、定数fooにいくつかの値を割り当てる必要がある(yield文で決定される).したがって、next(2)の第二回呼び出しの値foo=2です.プログラムはここで停止しません.次のyieldまたはreturn文に出会うまでずっと実行します.この例では、より多くのyieldがないので、2を記録してundefinedのdone:trueに戻る.生成器で非同期を使うと、yieldは双方向チャネルであるため、情報が両方の方向に流れることができます.だから、非常にクールな方法でジェネレータを使用することができます.私たちはこれまで、主にYieldを使ってジェネレータの外で値を伝えてきました.しかし、私たちは、yieldの双方向特性を利用して同期方式で非同期関数を作成することもできます. 上記の概念を使用して、同期コードと類似した基本関数を作成できます.
生成器は使い捨てです.
ジェネレータを繰り返し使用することはできませんが、ジェネレータ関数から新しいジェネレータを作成することができます.
ディケンサはシーケンスを表しています.配列に似ています.だから、私たちはすべてのサブジェネレータを配列として表示することができますよね?しかし、そうではない.配列は作成時にすぐに割り当てられます.配列は、n個の要素を含む配列を作成するには、まずすべてのn個の要素を作成/計算して、配列に格納する必要があるので、必要があります.対照的に、ディケンサは不活性です.シーケンスの次の値は使用時にのみ作成/計算されます.したがって、無限のシーケンスを表す配列は物理的に不可能であり(無限のメモリを必要として無限のアイテムを保存する!)、そして、そのシーケンスは、(記憶ではなく)簡単に表されることができる.1から無限までのシーケンスを作りましょう.配列と違って、これは無限メモリを必要としません.シーケンスの各値は使用時にのみだらだら計算されます.
見た後
もっと多くの人にもこの内容を見てもらいたいです.(収集はいいです.全部ごろつきです.-)公衆番号「新先端コミュニティ」に注目して、文章の最初の体験を楽しんでください.毎週重点的に先端技術の難点を攻略します.
概要
JavaScriptはES 6にジェネレータを導入した.ジェネレータ関数は、それらを一時停止および回復できる点を除いて、従来の関数と同様である.生成器も、サブジェネレータと密接に関係しています.生成器オブジェクトは、サブジェネレータです.JavaScriptでは、関数の呼び出し後は通常一時停止や停止ができません.(はい、非同期関数はawait文を待っている間は一時停止しますが、非同期関数はES 7の時に導入されます.また、非同期関数はジェネレータの上に構築されています.)一つの一般関数は、エラーが戻ったり投げ出されたりした時にのみ終了します.
function foo() {
console.log('Starting');
const x = 42;
console.log(x);
console.log('Stop me if you can');
console.log('But you cannot');
}
対照的に,生成器は,任意のブレークポイントでの実行を一時停止し,同じブレークポイントからの復帰を可能にした.ジェネレータとサブジェネレータ
MDNから来ました:
JavaScriptでは、ディケンサはオブジェクトであり、シーケンスを定義し、終了時には戻り値を返します.より具体的には、シーケンサは、next()方法を使用してIteratocolを実現する任意のオブジェクトであり、この方法は、2つの属性を有するオブジェクトを返す.これはシーケンス内のnext値である.とdoneは、シーケンスの最後の値に反復した場合、trueです.もしvalueとdoneが一緒に存在するならば、それはディズエバの戻り値です.
そのため、ディエテンダーの本質は:
next()
の方法があります.ジェネレータを作成しますか?いいえ.実際には、私たちはすでに閉包pre-ES 6を使用して、フィボナッチの無限数列を作成することができます.
var fibonacci = {
next: (function () {
var pre = 0, cur = 1;
return function () {
tmp = pre;
pre = cur;
cur += tmp;
return cur;
};
})()
};
fibonacci.next(); // 1
fibonacci.next(); // 2
fibonacci.next(); // 3
fibonacci.next(); // 5
fibonacci.next(); // 8
ジェネレータのメリットについては、MDNを再び参照します.カスタムディケンサは有用なツールですが、それらの内部状態を明示的に維持する必要があるので、それらを作成するには注意深くプログラミングする必要があります.ジェネレータ関数は、反復アルゴリズムを定義する連続ではない関数を作成することによって、強力な代替法を提供する.
言い換えれば、エラーの可能性がより小さいことを意味する、ジェネレータを使用して、より簡単に(パケットを閉じる必要がない!)を作成します.
ジェネレータとサブジェネレータとの関係は、ジェネレータ関数が返したジェネレータオブジェクトがサブジェネレータです.
構文
ジェネレータ関数は、function*文法を使って作成し、yieldキーを使って一時停止します.最初にジェネレータ関数を呼び出してもコードは実行されません.反対に、生成器オブジェクトを返します.この値は、ジェネレータのnext()メソッドを呼び出すことによって使用され、この方法は、yieldキーワードに出会うまでコードを実行し、その後、next()を再度呼び出すまで停止する.
function * makeGen() {
yield 'Hello';
yield 'World';
}
const g = makeGen(); // g is a generator
g.next(); // { value: 'Hello', done: false }
g.next(); // { value: 'World', done: false }
g.next(); // { value: undefined, done: true }
上の最後の文の後でg.next()を繰り返しますと、同じ戻り先に戻ります.yield一時停止実行
上のコードの断片にはいくつかの特殊な点があることに気づくかもしれません.2番目のnext()呼び出しは、done:trueではなく、done:falseのオブジェクトを生成します.私たちはジェネレータ関数で最後の文を実行していますが、done属性はtrueではないですか?わけではない.yield文に出会うと、その後ろの値(この例では「World」)が生成され、実行が一時停止されます.したがって、第二のnext()呼び出しは第二のyield文で一時停止されていますので、実行はまだ完了していません.第二のyield文の後に再起動を実行した場合のみ、実行は完了します.コードは再実行されません.next()を呼び出して、次のyield文(存在すると仮定して)プログラムに実行して、値を生成して、一時停止することができます.プログラムは実行を再開する前に、yield文の後には何の内容もなく、もう一つのnext()呼び出しで実行されます.
yieldとreturn
上記の例では、yieldを使用して、値を生成器の外部に渡す.私達もreturnを使ってもいいです.しかし、returnを使って実行を終了し、done:trueを設定することができます.
function * makeGen() {
yield 'Hello';
return 'Bye';
yield 'World';
}
const g = makeGen(); // g is a generator
g.next(); // { value: 'Hello', done: false }
g.next(); // { value: 'Bye', done: true }
g.next(); // { value: undefined, done: true }
実行は、return文では一時停止されませんし、定義により、return文の後はコードを実行することができませんので、doneはtrueに設定されます.yield:nextメソッドのパラメータ
私たちはこれまで、yield伝送生成器の外部の値を使っています.しかし、yieldは実際には双方向であり、値を生成器関数に伝達させることができる.
function * makeGen() {
const foo = yield 'Hello world';
console.log(foo);
}
const g = makeGen();
g.next(1); // { value: 'Hello world', done: false }
g.next(2); // logs 2, yields { value: undefined, done: true }
ちょっと待ってください.コンソールにプリントするべきではないですが、コンソールがプリントしたのは「2」ですか?最初は、この部分は概念的に直観とは逆であることを発見しました.予想されていたのはfoo=1です.なにしろ、私たちは「1」をnext()メソッド呼び出しに転送し、ハローワールドを生成するのですか?しかし事実はそうではない.最初のnext(...)に送る呼び出し値は破棄されます.これはES 6仕様のようですが、実際には他の理由はありません.意味的には、最初のnext方法はエルゴードオブジェクトを起動するために使用されますので、パラメータは必要ありません.このようにプログラムの実行を合理化するのが好きです.function request(url) {
fetch(url).then(res => {
it.next(res); // Resume iterator execution
});
}
function * main() {
const rawResponse = yield request('https://some-url.com');
const returnValue = synchronouslyProcess(rawResponse);
console.log(returnValue);
}
const it = main();
it.next(); // Remember, the first next() call doesn't accept input
これはその仕事の原理です.まず、request関数とmainジェネレータ関数を宣言します.続いて、Main()を呼び出して、ディケンサitを作成します.その後、私たちはit.next()を呼び出すことから始めます.第一行のfunction*main()は、yield request('https://some-url.com')その後、一時停止を実行します.request()はundefinedに暗黙的に戻り、したがって私たちは実際にundefined値を生成しましたが、これは重要ではありません.私たちはこの値を使っていません.request()関数のfetch()の呼び出しが完了すると、t.next(res)が呼び出され、次の二つのことを完了します.itは続けて実行します.とitは、RawResonseの最後に割り当てられた関数を生成器関数に伝達し、main()の残りの部分は同期されて完成される.これは非常に基本的な設定です.プロと似ているところがあります.yieldと非同期性についてもっと詳しく紹介しますので、この文を参照してください.生成器は使い捨てです.
ジェネレータを繰り返し使用することはできませんが、ジェネレータ関数から新しいジェネレータを作成することができます.
function * makeGen() {
yield 42;
}
const g1 = makeGen();
const g2 = makeGen();
g1.next(); // { value: 42, done: false }
g1.next(); // { value: undefined, done: true }
g1.next(); // No way to reset this!
g2.next(); // { value: 42, done: false }
...
const g3 = makeGen(); // Create a new generator
g3.next(); // { value: 42, done: false }
無限のシーケンスディケンサはシーケンスを表しています.配列に似ています.だから、私たちはすべてのサブジェネレータを配列として表示することができますよね?しかし、そうではない.配列は作成時にすぐに割り当てられます.配列は、n個の要素を含む配列を作成するには、まずすべてのn個の要素を作成/計算して、配列に格納する必要があるので、必要があります.対照的に、ディケンサは不活性です.シーケンスの次の値は使用時にのみ作成/計算されます.したがって、無限のシーケンスを表す配列は物理的に不可能であり(無限のメモリを必要として無限のアイテムを保存する!)、そして、そのシーケンスは、(記憶ではなく)簡単に表されることができる.1から無限までのシーケンスを作りましょう.配列と違って、これは無限メモリを必要としません.シーケンスの各値は使用時にのみだらだら計算されます.
function * makeInfiniteSequence() {
var curr = 1;
while (true) {
yield curr;
curr += 1;
}
}
const is = makeInfiniteSequence();
is.next(); { value: 1, done: false }
is.next(); { value: 2, done: false }
is.next(); { value: 3, done: false }
... // It will never end
興味深い事実:これはPython生成器式vsリスト理解と類似している.この2つの表式は機能的には同じですが、生成器式は値の計算が遅延しているためメモリの利点を提供します.リストの理解は即座に値を計算し、リスト全体を作成します.見た後
もっと多くの人にもこの内容を見てもらいたいです.(収集はいいです.全部ごろつきです.-)公衆番号「新先端コミュニティ」に注目して、文章の最初の体験を楽しんでください.毎週重点的に先端技術の難点を攻略します.