ホームページ >ウェブフロントエンド >jsチュートリアル >Javascriptのジェネレータ関数とyieldキーワード

Javascriptのジェネレータ関数とyieldキーワード

高洛峰
高洛峰オリジナル
2016-11-15 14:48:451338ブラウズ

注文

Javascript で誰もが最も議論するのは、非同期プログラミングの操作と、コールバックの多重ネストを回避する方法です。非同期操作のコールバックが多数ネストされると、コードが肥大化するだけでなく、エラーも発生しやすくなります。有名な Promise 社など、さまざまな非同期プログラミング ソリューションが常に提案されています。今日説明するジェネレーターとyieldは非同期プログラミングに関連しており、非同期プログラミングの同期に役立ちます。

ジェネレーターの概要

ジェネレーターは、関数と関数名の間に余分な * があることを除いて、フォーム上の関数に似ています。 yield キーワードはジェネレーター内で使用する必要があります。例:

function * gen(){
  var result1 = yield 'hello';
  var result2 = yield 'world';
  return result1 + result2;
}

ジェネレーター関数が呼び出されると、関数内のコードは実行されませんが、next メソッドを含むトラバーサーが返されます。次のメソッドが実行されるたびに、Generator 関数本体は実行を開始し、yield ステートメントに到達してステートメントを実行し、ここで一時停止します。使用法は次のとおりです。

var g = gen();
g.next(1);
//{value : 'hello', done : false}
g.next(2);
//{value : 'world', done : false}
g.next();
//{value : 3, done: true}
g.next();
//{value : undefined, done: true}

next メソッドを呼び出すと、オブジェクトが返されます。このオブジェクトには、value と Done という 2 つの属性が含まれています。Value は、現在の yield ステートメントの値です。 Done は、ジェネレーター関数本体が実行されたかどうかを示します。次のメソッドはパラメーターも受け入れます。このパラメーターは、yield ステートメントの戻り値として使用され、後続のプログラムで使用できます。プログラムの実行が終了するか、return ステートメントに遭遇すると、value は関数本体の戻り値となり、done は true になります。この時点で、次のメソッドが再度実行されると、value は未定義になり、done は true のままになります。

トラバーサルにおけるジェネレーターの応用

js では、配列をトラバースしたい場合、for...of のようなステートメントを使用してトラバースできます。これは、実際には配列にジェネレーター トラバーサーが含まれているためです。自己定義オブジェクトにトラバーサも含まれている場合は、for...of などのトラバーサル ステートメントを通じてカスタム オブジェクトをトラバースできます。このイテレータは、Symbol.iterator プロパティに保存されます。

var myArray = {
  0: '你',
  1: '的',
  2: '名字',
  length: 3
};

myArray[Symbol.iterator] = function * (){
  for(var i = 0; i < this.length; i++) {
    yield this[i];
  }
};

for(var item of myArray) {
  console.log(item);
}
//你
//的
//名字

非同期プログラミングにおけるジェネレーターの応用

Javascript の核心は非同期プログラミングであり、各非同期操作は実行結果を返すコールバック関数を提供します。いくつかの操作があり、後の操作が前の操作の結果に依存するとします。

step1(function(value1) {
  step2(value1, function(value2) {
    step3(value2, function(value3)) {
      //some code
    }
  });
})

このようなコードでは、ネストされたコールバックの数が増えると、プログラムが非常に理解しにくくなります。私たちがしなければならないのは、コールバックをフラット化することです。 Promise オブジェクトには、上記の操作を約束します。

step1().then(function(value1){
  return step2(value1);
}).then(function(value2){
  return step3(value2);
}).then(function(){
  //some code
})

入れ子が少なくなっていることがわかりますが、これは、非同期操作を同期操作に変えることができる場合、つまり、入れ子なしで行うことができる場合には、最も理想的な解決策ではありません。プログラムが理解しやすくなります。ジェネレーター機能はそのような機会を提供します。

function *workflow(){
  var value1 = yield step1();
  var value2 = yield step2();
  var value3 = yield step3();
  //some code
}

これが私たちが望む結果であり、非同期プログラミング プログラムは同期プログラミングの形式です。次に行う必要があるのは、このジェネレーターを実行させることなので、エグゼキューターが必要です。 co はエグゼキュータであり、Generator を自動的に実行できます。

co(function *workflow(){
  var value1 = yield step1();
  var value2 = yield step2();
  var value3 = yield step3();
  //some code
});

co には制限があります。yield ステートメントの後には Promise オブジェクトまたは Thunk 関数のみを続けることができます。co の詳細については、Ruan 先生の記事「co 関数ライブラリの意味と使用法」を参照してください。ただし、この方法でも外部ライブラリ関数に依存する必要があるため、ES6 では async および await キーワードが提案されました。 async と await は実際には Generator の構文シュガーです。専用のアクチュエーターが付属しているだけです。上記のコードを非同期形式に書き換えます:

async function workflow(){
  var value1 = await step1();
  var value2 = await step2();
  var value3 = await step3();
  //some code
}

var result = workflow();

async没有了co的限制。await关键字后面可以跟 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。