ES 6生成器を深く検討する
12308 ワード
ES 6生成器に慣れていない場合は、まずhttp://www.cnblogs.com/linda586586/p/4282359.htmlのコードを読んで実行してください.基礎を身につけたと感じたら、細部について深く検討します.
エラー処理
ES 6生成器設計において最も強力なのは、外部反復制御が非同期であっても、ジェネレータ内部コードの意味が同期されていることである.
簡単に使えるかもしれません.おなじみのエラー処理技術はtry-catchの仕組みです.
たとえば:
しかし、このジェネレータにエラーのフィードバックはどれぐらい正確ですか?
注:ジェネレータにエラーが発生しましたが、try-catchが捕獲されていません.エラーは元に戻ります.だから:
また、作成したいのは、ジェネレータ関数の内部から別のジェネレータを呼び出します.これは、生成器を一般的な方法で実装するだけでなく、実際には他のジェネレータエージェントに対して反復制御するという意味です.このようにするために、yieldキーワードの変形の一つを使用することができます.例:
しかし、yield*が遭遇しました.私たちはもう一つのジェネレータに実用化されていることに気づきます.だから、もう一つのジェネレータを反復して代理します.
yield*が*bar()から**foo()までエージェントを行う時、for-of循環のnext()呼び出しはコントロールfoo()ですが、yield 3とyield 4は彼らの値をfor-ofサイクルに送ります.
*foo()が終了すると、制御は元のジェネレータに戻り、最後にyield 5を呼び出します.
この例は簡略化して外向きのみにする.もちろん、for-ofサイクルを使わずに、手動でローズマリーのnext()を呼び出して、その情報を中に送ります.それらの情報は同じように望む方式で、yield*エージェントを通じて伝達されます.
もう一つのyieldがプレイできるアクションは、プロキシ生成器からreturn値を受信することである.
yieldとyield*は面白い違いがあります.yield表現を使って、結果は後のnextに送られましたが、yield*を使って、それはその代理のreturn値だけから結果を受けます.
両方の方向からエラー処理を行うこともできます.yield*エージェントを通じて:
締め括りをつける
ジェネレータには同期処理機構があります.すなわち、yield宣言によりtry-catchエラー処理が使用できます.ジェネレータ・ディケンサにも、ジェネレータが一時停止した位置でスローするthrow()方法があります.もちろん、ジェネレータ内部のtry-catchによって捕捉されても良いです.
yieldは、現在の生成器から別のプロキシ反復制御を可能にする.結果はyield*が二つの方向に伝達しています.情報でも間違いでもいいです.
しかし、もう一つの基本的な問題が残っています.答えがありません.ジェネレータはどうやってコードを同期する方式で助けてくれますか?私たちが今見ているこの二つの文章は、ジェネレータ関数の同期ローズマリーです.
鍵は、非同期タスクを起動するためのジェネレータを一時停止する仕組みを構築し、非同期タスクの最後に回復することである.このような非同期制御を生成する多くの方法を検討します.英文原文:http://davidwalsh.name/es6-generators-dive
エラー処理
ES 6生成器設計において最も強力なのは、外部反復制御が非同期であっても、ジェネレータ内部コードの意味が同期されていることである.
簡単に使えるかもしれません.おなじみのエラー処理技術はtry-catchの仕組みです.
たとえば:
function *foo() {
try {
var x = yield 3;
console.log( "x: " + x ); // may never get here!
}
catch (err) {
console.log( "Error: " + err );
}
}
関数がyield 3で一時停止しても、一時停止状態のいずれかの時間を維持します.もしジェネレータにエラーが発生したら、try-catchはそれをキャプチャします.通常の非同期法を用いて,コールバック関数のように処理してみた.しかし、このジェネレータにエラーのフィードバックはどれぐらい正確ですか?
var it = foo();
var res = it.next(); // { value:3, done:false }
// instead of resuming normally with another `next(..)` call,
// let's throw a wrench (an error) into the gears:
it.throw( "Oops!" ); // Error: Oops!
ローズマリーで使われているもう一つの方法――throw()は、ジェネレータに対して投げ間違いがあり、ジェネレータyieldの一時停止位置にちょうど発生しているようです.try-catch文は期待通りにエラーをキャッチしました.注:ジェネレータにエラーが発生しましたが、try-catchが捕獲されていません.エラーは元に戻ります.だから:
function *foo() { }
var it = foo();
try {
it.throw( "Oops!" );
}
catch (err) {
console.log( "Error: " + err ); // Error: Oops!
}
明らかに、逆方向のエラー処理も効果がありました.function *foo() {
var x = yield 3;
var y = x.toUpperCase(); // could be a TypeError error!
yield y;
}
var it = foo();
it.next(); // { value:3, done:false }
try {
it.next( 42 ); // `42` won't have `toUpperCase()`
}
catch (err) {
console.log( err ); // TypeError (from `toUpperCase()` call)
}
プロキシジェネレータまた、作成したいのは、ジェネレータ関数の内部から別のジェネレータを呼び出します.これは、生成器を一般的な方法で実装するだけでなく、実際には他のジェネレータエージェントに対して反復制御するという意味です.このようにするために、yieldキーワードの変形の一つを使用することができます.例:
function *foo() {
yield 3;
yield 4;
}
function *bar() {
yield 1;
yield 2;
yield *foo(); // `yield *` delegates iteration control to `foo()`
yield 5;
}
for (var v of bar()) {
console.log( v );
}
// 1 2 3 4 5
前のページで紹介したように、他の文章の中のyield*foo()に代わりました.発生していることをより正確に説明できると思います. これはどのように働いているのか見てみましょう.yield 1とyield 2は直接に彼らの値をfor of循環のnext()に送って呼び出して、私達の了解と期待のようです.しかし、yield*が遭遇しました.私たちはもう一つのジェネレータに実用化されていることに気づきます.だから、もう一つのジェネレータを反復して代理します.
yield*が*bar()から**foo()までエージェントを行う時、for-of循環のnext()呼び出しはコントロールfoo()ですが、yield 3とyield 4は彼らの値をfor-ofサイクルに送ります.
*foo()が終了すると、制御は元のジェネレータに戻り、最後にyield 5を呼び出します.
この例は簡略化して外向きのみにする.もちろん、for-ofサイクルを使わずに、手動でローズマリーのnext()を呼び出して、その情報を中に送ります.それらの情報は同じように望む方式で、yield*エージェントを通じて伝達されます.
function *foo() {
var z = yield 3;
var w = yield 4;
console.log( "z: " + z + ", w: " + w );
}
function *bar() {
var x = yield 1;
var y = yield 2;
yield *foo(); // `yield*` delegates iteration control to `foo()`
var v = yield 5;
console.log( "x: " + x + ", y: " + y + ", v: " + v );
}
var it = bar();
it.next(); // { value:1, done:false }
it.next( "X" ); // { value:2, done:false }
it.next( "Y" ); // { value:3, done:false }
it.next( "Z" ); // { value:4, done:false }
it.next( "W" ); // { value:5, done:false }
// z: Z, w: W
it.next( "V" ); // { value:undefined, done:true }
// x: X, y: Y, v: V
私たちはここで一つのエージェントを示しただけでも、*foo()は他のジェネレータではない理由がありません.そしてもう一つ、これに類推します.もう一つのyieldがプレイできるアクションは、プロキシ生成器からreturn値を受信することである.
function *foo() { yield 2; yield 3; return "foo"; // return value back to `yield*` expression } function *bar() { yield 1; var v = yield *foo(); console.log( "v: " + v ); yield 4; } var it = bar(); it.next(); // { value:1, done:false } it.next(); // { value:2, done:false } it.next(); // { value:3, done:false } it.next(); // "v: foo" { value:4, done:false } it.next(); // { value:undefined, done:true }
彼が終了するまで繰り返し制御(next()を代行し、foo()からの任意の戻り値をyield*式の結果として設定し、ローカル変数vに値を与えたことが見られます.yieldとyield*は面白い違いがあります.yield表現を使って、結果は後のnextに送られましたが、yield*を使って、それはその代理のreturn値だけから結果を受けます.
両方の方向からエラー処理を行うこともできます.yield*エージェントを通じて:
function *foo() {
try {
yield 2;
}
catch (err) {
console.log( "foo caught: " + err );
}
yield; // pause
// now, throw another error
throw "Oops!";
}
function *bar() {
yield 1;
try {
yield *foo();
}
catch (err) {
console.log( "bar caught: " + err );
}
}
var it = bar();
it.next(); // { value:1, done:false }
it.next(); // { value:2, done:false }
it.throw( "Uh oh!" ); // will be caught inside `foo()`
// foo caught: Uh oh!
it.next(); // { value:undefined, done:true } --> No error here!
// bar caught: Oops!
throw(「Uh oh!」)は*foo()内でyield*エージェントを通してtry-catchに間違って投げられました.*foo()内のthrow「Oops!」を投げ出して**barに戻し、もう一つのtry-catchで捕獲しました.彼らの中の一つを捕まえられなかったら、ミスは期待通りに外に伝播し続けます.締め括りをつける
ジェネレータには同期処理機構があります.すなわち、yield宣言によりtry-catchエラー処理が使用できます.ジェネレータ・ディケンサにも、ジェネレータが一時停止した位置でスローするthrow()方法があります.もちろん、ジェネレータ内部のtry-catchによって捕捉されても良いです.
yieldは、現在の生成器から別のプロキシ反復制御を可能にする.結果はyield*が二つの方向に伝達しています.情報でも間違いでもいいです.
しかし、もう一つの基本的な問題が残っています.答えがありません.ジェネレータはどうやってコードを同期する方式で助けてくれますか?私たちが今見ているこの二つの文章は、ジェネレータ関数の同期ローズマリーです.
鍵は、非同期タスクを起動するためのジェネレータを一時停止する仕組みを構築し、非同期タスクの最後に回復することである.このような非同期制御を生成する多くの方法を検討します.英文原文:http://davidwalsh.name/es6-generators-dive