web-dev-qa-db-ja.com

JavaScriptのyieldキーワードとは何ですか?

JavaScriptの「yield」キーワードについて聞いたが、非常に貧弱なドキュメントを見つけた。誰かが私にその使用方法とその用途を説明できますか(または説明するサイトを推奨します)?

208
mck89

MDNドキュメンテーション はかなり良いです、IMO。

Yieldキーワードを含む関数はジェネレーターです。呼び出すと、その仮パラメータは実際の引数にバインドされますが、本体は実際には評価されません。代わりに、ジェネレータイテレータが返されます。 generator-iteratorのnext()メソッドを呼び出すたびに、反復アルゴリズムを介して別のパスが実行されます。各ステップの値は、yieldキーワードで指定された値です。 yieldは、アルゴリズムの各反復間の境界を示すreturnのジェネレーター-イテレーターバージョンと考えてください。 next()を呼び出すたびに、ジェネレーターコードはyieldに続くステートメントから再開します。

80
Matt Ball

回答が遅く、おそらく誰もがyieldについて知っていますが、いくつかのより良いドキュメントが登場しました。

"Javascript's Future:Generators" からの例を、公式のHarmony規格に合わせてJames Longが修正:

function * foo(x) {
    while (true) {
        x = x * 2;
        yield x;
    }
}

「fooを呼び出すと、nextメソッドを持つGeneratorオブジェクトが返されます。」

var g = foo(2);
g.next(); // -> 4
g.next(); // -> 8
g.next(); // -> 16

yieldreturnのようなものです:何かを取り戻します。 return xxの値を返しますが、yield xは次の値に向かって反復するメソッドを提供する関数を返します。 潜在的にメモリ集中型の手順 があり、反復中に中断したい場合に便利です。

179
bishop

Nick Sotirosの答え(私は素晴らしいと思う)を単純化/詳細化するために、yieldでコーディングを開始する方法を説明するのが最善だと思います。

私の意見では、yieldを使用する最大の利点は、コードで見られるネストされたコールバックの問題をすべて排除できることです。最初はどのように見えるかわかりにくいので、この答えを書くことにしました(私自身、そしてできれば他の人も!)

それを行う方法は、必要なものが得られるまで自発的に停止/一時停止できる関数であるコルーチンの概念を導入することです。 JavaScriptでは、これはfunction*で示されます。 function*関数のみがyieldを使用できます。

典型的なjavascriptは次のとおりです。

loadFromDB('query', function (err, result) {
  // Do something with the result or handle the error
})

これは、すべてのコード(このloadFromDB呼び出しを待機する必要があるのは明らか)がこの見苦しいコールバック内にある必要があるためです。これはいくつかの理由で悪いです...

  • すべてのコードは1レベルインデントされます
  • この終わり})があり、どこでも追跡する必要があります
  • この余分なfunction (err, result)専門用語
  • resultに値を割り当てるためにこれを行っているかどうかは明確ではありません

一方、yieldを使用すると、これはすべて、ニースコルーチンフレームワークの助けを借りて、1行で実行できます。

function* main() {
  var result = yield loadFromDB('query')
}

そして今、あなたのメイン関数は、変数や物がロードされるのを待つ必要があるときに、必要な場所を生成します。しかし今、これを実行するには、normal(非コルーチン関数)を呼び出す必要があります。単純なコルーチンフレームワークでこの問題を修正できるので、これを実行するだけで済みます。

start(main())

開始が定義されています(Nick Sotiroの回答より)

function start(routine, data) {
    result = routine.next(data);
    if(!result.done) {
        result.value(function(err, data) {
            if(err) routine.throw(err); // continue next iteration of routine with an exception
            else start(routine, data);  // continue next iteration of routine normally
        });
    }
}

そして今、あなたははるかに読みやすく、削除が簡単で、インデントや関数などをいじる必要のない美しいコードを持つことができます。

興味深い観察結果は、この例では、yieldは実際にはコールバックを使用して関数の前に置くことができる単なるキーワードであるということです。

function* main() {
  console.log(yield function(cb) { cb(null, "Hello World") })
}

「Hello World」を印刷します。したがって、同じ関数シグネチャを(cbなしで)作成し、function (cb) {}を返すだけで、コールバック関数をyieldを使用して実際に変換できます。

function yieldAsyncFunc(arg1, arg2) {
  return function (cb) {
    realAsyncFunc(arg1, arg2, cb)
  }
}

この知識があれば、より簡潔で読みやすいコードを書くことができます 削除しやすい

52
Leander

それは本当に簡単です、これがどのように動作するかです

  • yieldキーワードは、一時停止および再開いつでも機能するのに役立ちます非同期
  • さらに、-ジェネレータ関数から戻り値に役立ちます。

この単純なgenerator関数を使用してください。

function* process() {
    console.log('Start process 1');
    console.log('Pause process2 until call next()');

    yield;

    console.log('Resumed process2');
    console.log('Pause process3 until call next()');

    let parms = yield {age: 12};
    console.log("Passed by final process next(90): " + parms);

    console.log('Resumed process3');
    console.log('End of the process function');
}

let _process = process();

let out1 = _process.next();
console.log(out1);

let out2 = _process.next();
console.log(out2);

let out3 = _process.next(90);
console.log(out3);

let _process = process();

_ process.next() itを呼び出すまでwontを実行最初の2行のコード、そしてfirst yieldpause関数になります。次へ再開関数まで一時停止ポイント(yieldキーワード)呼び出す必要があります- _ process.next()

複数のyieldsは、単一関数内のjavascriptデバッガーのbreakpointsと考えることができます。次のブレークポイントに移動するよう指示するまで、コードブロックは実行されません。 (:アプリケーション全体をブロックせずに)

しかし、yieldはこの一時停止と再開の動作を実行しますが、値を出力していない前の関数に従って結果を返す{value: any, done: boolean}を実行できます。前の出力を調べると、値ndefinedで同じ{ value: undefined, done: false }が表示されます。

Yieldキーワードを詳しく見てみましょう。オプションで、expressionを追加し、デフォルトのオプション値を割り当てるを設定できます。 (公式のドキュメント構文)

[rv] = yield [expression];

expression:ジェネレーター関数から返す値

yield any;
yield {age: 12};

rv:ジェネレータのnext()メソッドに渡されたオプションの値を返します

このメカニズムを使用してprocess()関数にパラメーターを渡すだけで、さまざまなyieldパーツを実行できます。

let val = yield 99; 

_process.next(10);
now the val will be 10 

今すぐ試す

使用法

  • 遅延評価
  • 無限のシーケンス
  • 非同期制御フロー

参照:

46
noelyahan

完全な答えを出すには:yieldreturnと同様ですが、ジェネレーターで機能しています。

一般的に与えられた例に関しては、これは次のように機能します:

function *squareGen(x) {
    var i;
    for (i = 0; i < x; i++) {
        yield i*i;
    }
}

var gen = squareGen(3);

console.log(gen.next().value); // prints 0
console.log(gen.next().value); // prints 1
console.log(gen.next().value); // prints 4

しかし、yieldキーワードのもう1つの目的もあります。ジェネレーターに値を送信するために使用できます。

明確にするために、小さな例を以下に示します。

function *sendStuff() {
    y = yield (0);
    yield y*y;
}

var gen = sendStuff();

console.log(gen.next().value); // prints 0
console.log(gen.next(2).value); // prints 4

これは、値2yに割り当てられ、最初のyield(0を返した)で停止した後、ジェネレーターに送信することで機能します。

これにより、本当にファンキーなものを作成できます。 (コルーチンを調べる)

17
David

イテレータジェネレータに使用されます。基本的に、プロシージャコードを使用して(潜在的に無限)シーケンスを作成できます。 Mozillaのドキュメント を参照してください。

16

yieldは、コルーチンフレームワークを使用して、コールバック地獄を排除するためにも使用できます。

function start(routine, data) {
    result = routine.next(data);
    if(!result.done) {
        result.value(function(err, data) {
            if(err) routine.throw(err); // continue next iteration of routine with an exception
            else start(routine, data);  // continue next iteration of routine normally
        });
    }
}

// with nodejs as 'node --harmony'
fs = require('fs');
function read(path) {
    return function(callback) { fs.readFile(path, {encoding:'utf8'}, callback); };
}

function* routine() {
    text = yield read('/path/to/some/file.txt');
    console.log(text);
}

// with mdn javascript 1.7
http.get = function(url) {
    return function(callback) { 
        // make xhr request object, 
        // use callback(null, resonseText) on status 200,
        // or callback(responseText) on status 500
    };
};

function* routine() {
    text = yield http.get('/path/to/some/file.txt');
    console.log(text);
}

// invoked as.., on both mdn and nodejs

start(routine());
6
Nick Sotiros

Yieldキーワードを使用したフィボナッチ数列ジェネレーター。

function* fibbonaci(){
    var a = -1, b = 1, c;
    while(1){
        c = a + b;
        a = b;
        b = c;
        yield c;
    }   
}

var fibonacciGenerator = fibbonaci();
fibonacciGenerator.next().value; // 0 
fibonacciGenerator.next().value; // 1
fibonacciGenerator.next().value; // 1
fibonacciGenerator.next().value; // 2 
4
nikksan

非同期javascript呼び出し間の依存関係。

利回りの使用方法のもう1つの良い例です。

function request(url) {
  axios.get(url).then((reponse) => {
    it.next(response);
  })
}

function* main() {
  const result1 = yield request('http://some.api.com' );
  const result2 = yield request('http://some.otherapi?id=' + result1.id );
  console.log('Your response is: ' + result2.value);
}

var it = main();
it.next()
3