ES 6のGenerator

18020 ワード

ES 6中Generator
GeneratorはES 6の興味深い特性であり、理解しにくい特性でもあります.let/constがブロックレベルのスコープを提供したという明白な目的とは違って、このようなものが作られたのは一体何ですか?
まず、JavaScriptにおいて、どの関数も実行を開始すると、実行が完了するまで停止できなくなります.
but,Generatorはこの能力を提供します.次のコードを見てください
function *g(){
    console.log('start');
    yield 1;
    console.log('middle');
    yield 2;
    console.log('end');
}
var g1 = g();
console.log(g1.next()); 
// start
// {value: 1, done: false}
console.log(g1.next());  
// middle
// {value: 2, done: false}
console.log(g1.next());  
// end
// {value: undefined, done: true}

出力結果によると、関数gyieldのキーワードがあり、実行中のプログラムが停止することを確認しました.関数next()のコードは、gの方法を呼び出してのみ実行される.したがって、関数g自体に一時停止状態がある.
ここに来て、私達は知る必要があります.
  • Generatorは関数ではなく、関数ではない.
  • g()はすぐに実行に出発しないで、上がってきたら一時停止して、Iteratorオブジェクトに戻ります.
  • 毎回g 1.next()は一時停止状態を破って実行します.次のyieldまたはreturn
  • に出会うまで.
  • がyieldに会った時、yeildの後の表現を実行して、実行後の値を返して、再度一時停止状態に入ります.この時done:false.
  • がreturnに会ったら、値を返します.実行が終了します.すなわちdone:true
  • 毎回g.next()の戻り値は永遠にすべてvalue:…,done:…)の形です.
    Generatorと非同期
    Generatorが関数を止められるなら、一部の脳洞清奇な人はGeneratorで非同期プログラムを処理してもいいかと思いました.
    まず伝統的な例を見ます.
        function asyn(fn) {
            return new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    fn();
                    resolve(true);
                }, 1000);
            });
        }
    
        function main() {
            console.log('start');
            asyn(function(d) {
                console.log('async one');
                asyn(function(d) {
                    console.log('async two');
                    console.log('end');
                });
            });
        }
    
        main();
    
    また、Generatorを使った非同期プログラムを見てください.
        function asyn(fn) {
            return new Promise((resolve,reject)=>{
                setTimeout(()=>{
                    fn();
                    resolve(true);
                }, 1000);
            });
        }
    
        co(function*() {
            console.log('start');
            yield asyn(function(d) {
                console.log('async one');
            });
    
            yield asyn(function(d) {
                console.log('async two');
            });
            console.log('end');
        });
    
        function co(fn) {
    
            return new Promise((resolve,reject)=>{
                let g = fn();
    
                onFullfilled();
                function onFullfilled() {
                    let ret = null;
                    ret = g.next();
                    next(ret);
                }
    
                function next(ret) {
                    if(ret.done) return resolve(ret.value);
                    ret.value.then(onFullfilled);
                }
            } );
        }
    
    関数は非同期プログラムに入れ子のコールバックを使用していません.直接同期方式で書きました.道理は大体、二つの非同期プログラムがあります.明と紅を使ってそれらを指します.紅ちゃんは明さんの実行が終わったら実行できます.そうすると、私達は明さんに実行する時、プログラムの実行を一時停止します.(yieldを通じて)明さんが帰ってきた時、後に付いてくる紅ちゃんを実行します.
    上記の手順では、next()関数を追加しました.この関数の役割はGeneratorに自動的に実行させます.直接的には、第1の非同期関数が戻った後に、自動的にcoメソッドを呼び出して、後のコードを実行します.
    GeneratorとKooa
    KooaはNode.jsに基づくWebアプリケーションのフレームワークである.Kooでは、処理の非同期プログラムは、主にネットワーク要求(HTTP)、ファイル読み込み、およびデータクエリである.この中の非同期シーンが多いです.プログラムの階層を加えて、伝統的なcalback方式を採用すると、その回数が多くなります.
    app.on('get', function(){
        auth(function(){
            router(function(){
                find(function(){
                    save(function(){
                        render(function(){
                            //......
                        })
                    })
                })
            })
        })
    
    })
    
    このような書き方はプログラムの維持と不利で、便利さがまったくないです.generatorができたら、上のようにプログラムを書くことができます.Koraの最初のバージョンはこのようにして中間処理プログラムを一つずつ「yield」(中間部品)にします.中間部品の形式でクライアント要求を処理することにより、開発Appアプリケーションをより柔軟にし、フレーム自体に制限されない.
    最新のKoo 2ではGenetatorを捨ててnext()を使用します.
    しかし、どのような方式を採用しても、その本質はPromiseを利用したのです.