JavaScriptのシンボル、ジェネレーター、非同期/待機、および非同期イテレーター:その性質、関係、およびユースケース

多くのJavaScript機能の性質と目的は非常に明白です。 しかし、発電機のような一部のものは、一見すると奇妙に見えるかもしれません。 プリミティブ型とオブジェクトの値に類似したシンボルは、同じ印象を与える可能性があります。 ただし、プログラミング言語は全体的なシステムであり、一部の機能は他の機能に依存しています。 したがって、通常、1つのものを完全に理解することは、それが何に関連し、何に依存し、何に影響するかを理解することなしに不可能です。



画像



今日公開している資料は、シンボル、よく知られているシンボル、反復子、反復可能オブジェクト、ジェネレーター、非同期/待機メカニズム、非同期反復子などのJavaScriptメカニズムと構造を説明することを目的としています。 特に、ここでそれらが言語に登場した理由と、それらの使用方法について説明します。 ここで取り上げるトピックは、JavaScriptをある程度理解している人向けに設計されていることに注意してください。



シンボルと有名なシンボル



ES2015では、新しい6番目のデータ型-symbolが導入されました。 なんで? このデータ型が表示される主な理由は3つあります。



▍理由番号1。 下位互換性を備えた基本機能の拡張



JavaScript開発者とECMAScript委員会(TC39)は、 for-in



ループやObject.keys



などのメソッドなど、既存のメカニズムを中断することなく、オブジェクトに新しいプロパティを追加する機能を必要としていObject.keys







次のようなオブジェクトがあるとします:



 var myObject = {firstName:'raja', lastName:'rao'}
      
      





Object.keys(myObject)



コマンドを実行すると、配列[firstName, lastName]



が返されます。



次に、別のプロパティ、たとえばnewProperty



myObject



オブジェクトに追加します。 同時に、以前と同じ値を返すためにObject.keys(myObject)



コマンドが必要Object.keys(myObject)



つまり、この関数で新しいプロパティnewProperty



無視する必要がある)、つまり[firstName, lastName]



、 not [ firstName, lastName, newProperty]



。 どうやってやるの?



実際、 symbol



データ型が出現する前は、これは不可能でした。 これで、 newProperty



をシンボルとして追加すると、 Object.keys(myObject)



コマンドObject.keys(myObject)



このプロパティObject.keys(myObject)



無視し(単にそれを知らないため)、必要なものを返します- [firstName, lastName]







▍理由番号2。 名前の衝突回避



JavaScriptの開発に携わる人々は、オブジェクトの新しいプロパティが一意であることを望んでいます。 これにより、名前の衝突を心配することなく、グローバルオブジェクトに新しいプロパティを追加し続けることができます(JSを使用して実際の問題を解決する開発者も同じことができます)。



たとえば、プロジェクトに取り組んでいて、独自のtoUpperCase



メソッドをArray.prototype



に追加することにしたとします。



Array.prototype.toUpperCase



メソッドのバージョンがある特定のライブラリをプロジェクトに接続した(またはES2019が出た)ことを想像してください。 これにより、コードが正しく動作しなくなるという事実につながる可能性があります。



例を考えてみましょう。



 Array.prototype.toUpperCase = function(){   var i;   for (i = 0; i<this.length; i++){       this[i] = this[i].toUpperCase();   }   return this; } var myArray = ['raja', 'rao']; myArray.toUpperCase(); //['RAJA', 'RAO']
      
      





開発者がその存在を認識していない場合、そのような衝突を解決する方法は? ここでシンボルが助けになります。 一意の識別子が内部に作成され、名前の衝突を心配することなく、オブジェクトに新しいプロパティとメソッドを追加できます。



▍理由番号3。 プログラマーが独自に開発したメソッドの言語の標準メカニズムによる呼び出しの編成



String.prototype.search



などの標準関数が、文字列内の何かを検索するロジックを実装する独自の関数を呼び出すと仮定します。 つまり、たとえば、構文'somestring'.search(myObject);



が必要'somestring'.search(myObject);



myObject



search



関数を呼び出し、引数として'somestring'



を渡します。 どうやってやるの?



ES2015の機能が役立つのはこのような状況です。この場合、「既知のシンボル」と呼ばれる多くのグローバルシンボルがあります。 オブジェクトにこれらの文字のいずれかで表されるプロパティがある場合、標準関数を使用して関数の呼び出しを整理できます。 以下では、このメカニズムをより詳細に検討します。これを行う前に、シンボルの操作方法について説明します。



charactersキャラクターの作成



グローバルSymbol



関数を呼び出すことにより、新しいシンボルを作成できます。 この関数は、 symbol



型の値を返します。



 // mySymbol   symbol var mySymbol = Symbol();
      
      





シンボルにはメソッドがあるため、オブジェクトと間違われる可能性がありますが、オブジェクトではないことに注意してください。 これらはプリミティブな値です。 それらは、いくつかの「特別な」オブジェクトと考えることができます。これは、通常のオブジェクトに多少似ていますが、動作が異なります。



たとえば、シンボルにはオブジェクトに関連するメソッドがありますが、オブジェクトとは異なり、シンボルは不変で一意です。



charactersキャラクターと新しいキーワードの作成



シンボルはオブジェクトではないため、 new



キーワードを使用すると新しいオブジェクトが返されることが予想されるため、 new



キーワードを使用してsymbol



型のエンティティを作成することはできません。



 var mySymbol = new Symbol(); // ,    
      
      





characters文字の「説明」



シンボルの「説明」と呼ばれるものは文字列として表示され、ロギングに使用されます。



 // mySymbol    , //   -  "some text" const mySymbol = Symbol('some text');
      
      





▍ユニークなキャラクター



同じ記述を使用してシンボルを作成しても、シンボルは一意です。 このステートメントは、次の例で説明できます。



 const mySymbol1 = Symbol('some text'); const mySymbol2 = Symbol('some text'); mySymbol1 == mySymbol2 // false
      
      





SymbolSymbol.forメソッドを使用した文字の作成



Symbol()



関数を使用してSymbol()



型の変数を作成する代わりに、 Symbol.for(<key>)



メソッドを使用してSymbol.for(<key>)



作成できます。 このメソッドはキー(文字列<key>



)を受け取り、新しい文字を作成します。 同時に、既存のシンボルに既に割り当てられているキーがこのメソッドに既に割り当てられている場合、この既存のシンボルが返されます。 したがって、 Symbol.for



の動作はシングルトンデザインパターンに似ていると言えます。



 var mySymbol1 = Symbol.for('some key'); //   var mySymbol2 = Symbol.for('some key'); //     mySymbol1 == mySymbol2 //true
      
      





Symbol.for



メソッドが存在するため、ある場所でシンボルを作成し、別の場所でそれらを操作できます。



.for()



メソッドの機能は、すでに使用されているキーを渡すと、そのキーで新しいキャラクターを作成せずに、既存のキーを返すことに注意してください。 したがって、注意して使用してください。



▍キーとキャラクターの説明



Symbol.for



コンストラクトを使用しない場合、シンボルは、同じキーを使用する場合でも一意になることに注意してください。 ただし、 Symbol.for



を使用するSymbol.for



、一意でないキーを指定すると、 Symbols.for



によって返されるシンボルはSymbols.for



はなくなります。 例を考えてみましょう。



 var mySymbol1 = Symbol('some text'); //     "some text" var mySymbol2 = Symbol('some text'); //     "some text" var mySymbol3 = Symbol.for('some text'); //     "some text" var mySymbol4 = Symbol.for('some text'); //   ,    mySymbol3 //    true, //        .for //       mySymbol3 == mySymbol4 //true //    mySymbol1 == mySymbol2 //false mySymbol1 == mySymbol3 //false mySymbol1 == mySymbol4 //false
      
      





propertyプロパティプロパティの識別子としての文字の使用



文字はオブジェクトのように見えますが、プリミティブな値です。 おそらく、これらのユニークな機能が最も混乱を招きます。 特に、文字はオブジェクトのプロパティの識別子として使用できます。これには文字列が使用されます。



実際、オブジェクトプロパティ識別子は、シンボルの主な用途の1つです。



 const mySymbol = Symbol("Some car description"); const myObject = {name: 'bmw'}; myObject[mySymbol] = 'This is a car'; //      //    console.log(myObject[mySymbol]); //'This is a car'
      
      





シンボルであるオブジェクトのプロパティは、「シンボルキー付きプロパティ」または「シンボルキーを持つプロパティ」と呼ばれます。



▍ポイントと角括弧



シンボルであるオブジェクトのプロパティを操作する場合、この演算子は文字列で指定されたプロパティの操作にのみ適しているため、ピリオドは使用できません。 代わりに、そのような状況では角括弧を使用する必要があります。



 let myCar = {name: 'BMW'}; let type = Symbol('store car type'); myCar[type] = 'A_1uxury_Sedan'; let honk = Symbol('store honk function'); myCar[honk] = () => 'honk'; // myCar.type; //  myCar[type]; // 'store car type' myCar.honk(); //  myCar[honk](); // 'honk'
      
      





symbolsなぜシンボルを使用するのですか?



シンボルの仕組みを学習したので、シンボルを使用する3つの主な理由を繰り返して考え直しましょう。



理由1。 オブジェクトプロパティ識別子として使用されるシンボルは、ループや他のメソッドからは見えません。



次の例では、 for-in



ループはobj



オブジェクトのプロパティをループしますが、 prop3



およびprop4



プロパティは認識しません(またはこれらのプロパティを無視します)。これらの識別子は文字で表されるためです。



 var obj = {}; obj['prop1'] = 1; obj['prop2'] = 2; //     -, //   (    //   ) var prop3 = Symbol('prop3'); var prop4 = Symbol('prop4'); obj[prop3] = 3; obj[prop4] = 4; for(var key in obj){   console.log(key, '=', obj[key]); } //   ,     //   prop3  prop4 //prop1 = 1 //prop2 = 2 //   prop3  prop4  , //   console.log(obj[prop3]); //3 console.log(obj[prop4]); //4
      
      





以下は、 Object.keys



およびObject.getOwnPropertyNames



が文字で表されるプロパティ名を無視する別の例です。



 const obj = {   name: 'raja' }; //     - obj[Symbol('store string')] = 'some string'; obj[Symbol('store func')] = () => console.log('function'); //  -   //  console.log(Object.keys(obj)); //[name] console.log(Object.getOwnPropertyNames(obj)); //[name]
      
      





理由番号2。 シンボルはユニークです



独自のArray.prototype.includes



メソッドをプロトタイプに追加して、グローバルArray



オブジェクトを拡張する必要があるとします。 このメソッドは、JavaScript ES2018に存在する標準のincludeメソッドと競合します。 この方法でプロトタイプを提供し、衝突を避ける方法は?



最初includes



、includesという変数を作成して、それにシンボルを割り当てる必要があります。 次に、この変数を使用して、括弧表記を使用して新しいプロパティをグローバルArray



オブジェクトに追加する必要があります。 この後、必要な機能を新しいプロパティに割り当てるだけです。



新しい関数を呼び出すには、角括弧を使用する必要があります。 さらに、括弧内では、対応する変数の名前、つまりarr[includes]()



ようなものを使用する必要があり、通常の文字列ではないことに注意してください。



 var includes = Symbol('will store custom includes method'); //    Array.prototype Array.prototype[includes] = () => console.log('inside includes func'); // var arr = [1,2,3]; //       // includes console.log(arr.includes(1)); //true console.log(arr['includes'](1)); //true //       includes arr[includes](); // 'inside includes func',   includes -  
      
      





理由番号3。 既知のシンボル(グローバルシンボル)



デフォルトでは、JavaScriptは多くのシンボル変数を自動的に作成し、それらをグローバルSymbol



オブジェクトに書き込みます(新しいシンボルの作成に使用したものと同じオブジェクトについて話します)。



ECMAScript 2015では、これらの文字を使用して、 String



Array



などString.prototype.replace



標準オブジェクトのString.prototype.search



String.prototype.replace



などの基本メソッドをString.prototype.search



します。



そのようなシンボルの例を次に示しますSymbol.match



Symbol.replace



Symbol.search



Symbol.iterator



およびSymbol.split







これらの文字はグローバルで公開されているため、標準オブジェクトメソッドが内部メソッドではなく独自の関数を呼び出すようにすることができます。



例1 Symbol.searchの使用



String.prototype.search



オブジェクトのパブリックString.prototype.search



メソッドは、正規表現またはサンプル文字列を使用して文字列を検索し、必要なものを見つけることに成功した場合、分析中の文字列の検索のインデックスを返します。



 'rajarao'.search(/rao/); 'rajarao'.search('rao');
      
      





ES2015では、このメソッドは最初にSymbol.search



メソッドがRegExp



オブジェクトにSymbol.search



れているかどうかを確認します。 その場合、検索が実行されるのはRegExp



オブジェクトメソッドです。 したがって、 RegExp



などの基本オブジェクトは、検索の問題を解決するSymbol.search



に対応するメソッドを実装します。



▍内部メカニズムSymbol.search(標準動作)



文字列内の部分文字列を見つけるプロセスは、次の手順で構成されます。



  1. コマンド'rajarao'.search('rao');





  2. 文字シーケンス"rajarao"



    String (new String("rajarao"))



    オブジェクトに変換されますString (new String("rajarao"))





  3. 文字シーケンス"rao"



    RegExp (new Regexp("rao"))



    オブジェクトに変換されますRegExp (new Regexp("rao"))





  4. 文字列"rajarao"



    基づくString



    オブジェクトのsearch



    メソッド"rajarao"





  5. Symbol.search



    オブジェクトのsearch



    メソッド内で、 Symbol.search



    オブジェクトのSymbol.search



    メソッドが呼び出されます(つまり、検索操作の実行はSymbol.search



    オブジェクトに委任されます)。 文字列"rajarao"



    このメソッドに渡されます。 この呼び出しを図式的に表すと、次のようになります。 "rao"[Symbol.search]("rajarao")



  6. "rao"[Symbol.search]("rajarao")



    は、検索結果として、文字列内の部分文字列のインデックスを表す数値4、 "rajarao"



    オブジェクトのsearch



    関数を返し、この関数はコードに4を返します。


以下は、上記の標準JavaScriptオブジェクトの内部メカニズムの構造を示す擬似コードで記述されたスニペットです。



 //  String class String {   constructor(value){       this.value = value;   }   search(obj){       //  Symbol.search  obj          // value       obj[Symbol.search](this.value);   } } //  RegExp class RegExp {   constructor(value){       this.value = value;   }   //     [Symbol.search](string){       return string.indexOf(this.value);   } }
      
      





最も興味深いのは、同様の状況でRegExp



オブジェクトを使用することがオプションになったことです。 標準のString.prototype.search



関数String.prototype.search



、開発者が必要とするものを返すSymbol.search



メソッドを実装するオブジェクトを正しく認識String.prototype.search



ようになりました。これにより、コードが混乱することはありません。 これについてさらに詳しく説明します。



例2 Symbol.searchを使用して、標準関数から独自の開発関数の呼び出しを整理する



次の例は、 String.prototype.search



関数String.prototype.search



独自のProduct



クラスの検索関数をString.prototype.search



方法を示しています。 これは、グローバルSymbol.search



シンボルのおかげで可能です。



 class Product {   constructor(type){       this.type = type;   }   //     [Symbol.search](string){       return string.indexOf(this.type) >=0 ? 'FOUND' : "NOT_FOUND";   } } var soapObj = new Product('soap'); 'barsoap'.search(soapObj); //FOUND 'shampoo'.search(soapObj); //NOT_FOUND
      
      





▍内部Symbol.searchメカニズム(カスタム動作)



オブジェクトを1行で「検索」すると、次のアクションが実行されます。



  1. コマンド'barsoap'.search(soapObj);





    文字シーケンス"barsoap"



    String



    オブジェクトに変換されます( new String("barsoap")



  2. soapObj



    すでにオブジェクトであるため、変換されません
  3. "barsoap"



    文字列に基づくString



    オブジェクトのsearch



    メソッド"barsoap"



  4. このメソッド内で、 Symbol.search



    オブジェクトのSymbol.search



    メソッドがsoapObj



    (検索操作はこのオブジェクトに委任されます)、文字列"barsoap"



    。 実際、次のようなコマンドについて話している: soapObj[Symbol.search]("barsoap")





    soapObj[Symbol.search]("barsoap")







    soapObj[Symbol.search]("barsoap")



    は、 soapObj



    オブジェクトの内部ロジックに従って、値FOUND



    およびNOT_FOUND



    取得できるsearch



    関数を返します。 search



    関数はこの結果をコードに返します。


シンボルを理解したので、イテレーターを扱います。



反復子と反復可能オブジェクト



まず、なぜこれが必要なのかを自問します。 ここでの事実は、ほとんどすべてのアプリケーションでデータリストを操作する必要があるということです。 たとえば、これらのリストは、通常のWebページまたはモバイルアプリケーションに表示する必要があります。 通常、開発者はそのようなリストからデータを保存および取得するための独自のメソッドを作成します。



ただし、 for-of



ループや拡張演算子(



)など、配列、文​​字列、 Map



型のオブジェクトなどの標準オブジェクトからデータセットを抽出するように設計された標準言語メカニズムが既に用意されています。 これらの標準的な方法を使用して、データセットを保存する独自のオブジェクトを操作しないのはなぜですか?



次の例は、 for-of



ループと拡張演算子を使用して、自分で作成したUser



クラスからデータを取得できないことを示しています。 ここで、それを操作するには、 get



メソッドを使用する必要があります。これは、私たち自身も作成しました。



 //    //      for-of  //       //   Users,    //  class Users {   constructor(users){       this.users = users;   }   //     get() {       return this.users;   } } const allUsers = new Users([   { name: 'raja' },   { name: 'john' },   { name: 'matt' }, ]); // allUsers.get() ,     for (const user of allUsers){   console.log(user); } //    TypeError: allUsers is not iterable //    const users = [...allUsers]; //    TypeError: allUsers is not iterable
      
      





独自のオブジェクトを操作するために、標準の言語メカニズムを使用できると便利です。 これを実現するには、標準のJSツールで使用できるオブジェクトを作成するときに開発者が従うことができるルールが必要です。



実際、そのようなルールが存在します。 オブジェクトからデータを抽出する機能について説明します。 これらのルールに従って構築されたオブジェクトはiterables



と呼ばれます。



これらは規則です:



  1. メインのオブジェクト/クラスはいくつかのデータを保存する必要があります。
  2. 3〜6節で説明されているメソッドを実装する既知のSymbol.iterator



    シンボルであるプロパティが必要です。

  3. Symbol.iterator



    メソッドは、別のオブジェクト-イテレータを返す必要があります。

  4. 反復子にはnext



    メソッドが必要です。
  5. next



    方法では、段落1で説明したデータにアクセスする必要があります。

  6. next



    メソッドを呼び出すとき、イテレータが他の何かを返すことができる場合は{value:<stored data>, done: false}



    の形式で、または{done: true}



    の形式でステップ1のデータを返す必要があり{done: true}



    イテレータにはこれ以上返すものはありません。


これらの要件がすべて満たされている場合、メインオブジェクトは反復可能と呼ばれ、それが返すオブジェクトは反復子と呼ばれます。



次に、 Users



オブジェクトを反復可能にする方法について説明します。



 //   // Users   ,     // Symbol.iterator,      next, //       class Users{   constructor(users){       this.users = users;   }   // Symbol.iterator -  ,     //    [Symbol.iterator](){       let i = 0;       let users = this.users;       //           return {           next(){               if (i<users.length) {                   return { done: false, value: users[i++] };               }               return { done: true };           },       };   } } //allUsers    const allUsers = new Users([   { name: 'raja' },   { name: 'john' },   { name: 'matt' }, ]); //allUsersIterator   const allUsersIterator = allUsers[Symbol.iterator](); // next      , //    console.log(allUsersIterator.next()); console.log(allUsersIterator.next()); console.log(allUsersIterator.next()); //     : //{ done: false, value: { name: 'raja' } } //{ done: false, value: { name: 'john' } } //{ done: false, value: { name: 'matt' } } //  for-of for(const u of allUsers){   console.log(u.name); } //   : raja, john, matt //   console.log([...allUsers]); //    
      
      





, ( allUsers



) for-of



, <iterable>[Symbol.iterator]()



, ( allUsersIterator



), .



.





:



  1. .
  2. , , .


.



№1.



, , , - (generator), .



.



  1. - , *<myGenerator>



    . - function * myGenerator(){}



  2. myGenerator()



    generator



    , () , , , iterator



    .
  3. yield



    .
  4. yield



    , .
  5. yield



    , , next



    .


№1. - Symbol.iterator



- ( *getIterator()



) Symbol.iterator



next()



, .



 //     ,  //  - (*getIterator()) //      class Users{   constructor(users) {       this.users = users;       this.len = users.length;   }   // ,      *getIterator(){       for (let i in this.users){           yield this.users[i];           //     ,           //yield             }   } } const allUsers = new Users([   { name: 'raja' },   { name: 'john' },   { name: 'matt' }, ]); //allUsersIterator   const allUsersIterator = allUsers.getIterator(); // next      , //    console.log(allUsersIterator.next()); console.log(allUsersIterator.next()); console.log(allUsersIterator.next()); console.log(allUsersIterator.next()); //     : //{ done: false, value: { name: 'raja' } } //{ done: false, value: { name: 'john' } } //{ done: false, value: { name: 'matt' } } //{ done: true, value: undefined } //  for-of for(const u of allUsers.getIterator()){   console.log(u.name); } //   : raja, john, matt //   console.log([...allUsers.getIterator()]); //    
      
      





№2. -



-. , , , . - ( *



) yield



.



 // Users -  ,    function* Users(users){   for (let i in users){       yield users[i++];       //     ,       //yield         } } const allUsers = Users([   { name: 'raja' },   { name: 'john' },   { name: 'matt' }, ]); // next      , //    console.log(allUsers.next()); console.log(allUsers.next()); console.log(allUsers.next()); console.log(allUsers.next()); //     : //{ done: false, value: { name: 'raja' } } //{ done: false, value: { name: 'john' } } //{ done: false, value: { name: 'matt' } } //{ done: true, value: undefined } const allUsers1 = Users([   { name: 'raja' },   { name: 'john' },   { name: 'matt' }, ]); //  for-of for(const u of allUsers1){   console.log(u.name); } //   : raja, john, matt const allUsers2 = Users([   { name: 'raja' },   { name: 'john' },   { name: 'matt' }, ]); //   console.log([...allUsers2]); //    
      
      





, «iterator» allUsers



, , , Generator



.



Generator



throw



return



, next



. , , .



▍ №2.



, , , .



, , , yield



( , ) , , , yield



.



, , - yield



, . , generator.next("some new value")



, yield



.





-



, , .



 function* generator(a, b){   //  a + b   // ,   k   ,     //  a + b   let k = yield a + b;   //      m   let m = yield a + b + k;   yield a + b + k + m; } var gen = generator(10, 20); //   a + b //   ,  done   false,   //      yield console.log(gen.next()); //{value: 30, done: false} //      ,     //a  b,    .next() ,    - //,      ,    // //  k 50      a + b + k console.log(gen.next(50)); //{value: 80, done: false} //     ,     a, b  k. //  .next()      ,  //     ,     //  m 100      a + b + k + m console.log(gen.next(100)); //{value: 180, done: false} //   .next(),   undefined,     //    yield console.log(gen.next()); //{value: undefined, done: true}
      
      







.



 // //  - function *myGenerator() {} // function * myGenerator() {} // function* myGenerator() {} //  const myGenerator = function*() {} //   ,  //      let generator = *() => {} //      //SyntaxError: Unexpected token * //   ES2015 class MyClass {   *myGenerator() {} } //    const myObject = {   *myGenerator() {} }
      
      





▍ yield return



yield



, return



. , , return



, . , yield



, .



 function* myGenerator() {   let name = 'raja';   yield name;   console.log('you can do more stuff after yield'); } //   const myIterator = myGenerator(); // .next()    console.log(myIterator.next()); //{value: "raja", done: false} // .next()   //      // 'you can do more stuff after yield'    //{value: undefined, done: true} console.log(myIterator.next());
      
      





▍ yield



yield



, , return



, , yield



.



 function* myGenerator() {   let name = 'raja';   yield name;    let lastName = 'rao';   yield lastName; } //   const myIterator = myGenerator(); // .next()    console.log(myIterator.next()); //{value: "raja", done: false} // .next()   console.log(myIterator.next()); //{value: "rao", done: false}
      
      





▍ next



.next()



.



, , , ( ). , , redux-saga .



.next()



, ( ). ( 23



), .next(23)



.



 function* profileGenerator() {   //  .next()   ,     //,    yield,   .   //     ,  ,     //  .next(),     answer   let answer = yield 'How old are you?';   // 'adult'  'child'       // answer   if (answer > 18){       yield 'adult';   } else {       yield 'child';   } } //   const myIterator = profileGenerator(); console.log(myIterator.next()); //{value: "How old are you?", done: false} console.log(myIterator.next(23)); //{value: "adult", done: false}
      
      







, .



, , co , , , .next()



. , .



, co



.next(result)



№5 10, .



 co(function *() {   let post = yield Post.findByID(10);   let comments = yield post.getComments();   console.log(post, comments); }).catch(function(err){   console.error(err); });
      
      









  1. co



    , ,
  2. Post.findByID(10)



  3. Post.findByID(10)



  4. , , .next(result)



  5. post



  6. post.getComments()



  7. post.getComments()



  8. , , .next(result)



  9. comments



  10. console.log(post, comments);





async/await.



async/await



, , , , , co



. , — , ECMAScript , . async



await



.

async/await.



  1. async/await await



    yield



    .
  2. await



    .
  3. async function



    , function*



    .



, async/await



— , « ».



async



, , JavaScript- , -. , , await



. , await



, , .



getAmount



getUser



getBankBalance



. , async/await .



 //  ES2015... function getAmount(userId){   getUser(userId)       .then(getBankBalance)       .then(amount => {           console.log(amount);       }); } //  async/await ES2017 async function getAmount2(userId){   var user = await getUser(userId);   var amount = await getBankBalance(user);   console.log(amount); } getAmount('1'); //$1,000 getAmount2('1'); //$1,000 function getUser(userId){   return new Promise(resolve => {       setTimeout(() => {           resolve('john');       }, 1000);   }); } function getBankBalance(user){   return new Promise((resolve, reject) => {       setTimeout(() => {           if (user == 'john'){               resolve('$1,000');           } else {               reject('unknown user');           }       }, 1000);   }); }
      
      







. ES2018 ( ) TC39 Symbol.asyncIterator



, — for-await-of



, .



.





  1. .next()



    {value: 'some val', done: false}





  2. : iterator.next() //{value: 'some val', done: false}







.next()



, , , {value: 'some val', done: false}



.



:



 iterator.next().then(({ value, done })=> {//{value: 'some val', done: false}}
      
      





for-await-of



.



 const promises = [   new Promise(resolve => resolve(1)),   new Promise(resolve => resolve(2)),   new Promise(resolve => resolve(3)), ]; //       , //           async function test(){   for await (const p of promises){       console.log(p);   } } test(); //1, 2, 3
      
      





まとめ



JavaScript, , , . .





親愛なる読者! , , ?






All Articles