今日公開している資料は、シンボル、よく知られているシンボル、反復子、反復可能オブジェクト、ジェネレーター、非同期/待機メカニズム、非同期反復子などの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(標準動作)
文字列内の部分文字列を見つけるプロセスは、次の手順で構成されます。
- コマンド
'rajarao'.search('rao');
- 文字シーケンス
"rajarao"
String (new String("rajarao"))
オブジェクトに変換されますString (new String("rajarao"))
- 文字シーケンス
"rao"
RegExp (new Regexp("rao"))
オブジェクトに変換されますRegExp (new Regexp("rao"))
- 文字列
"rajarao"
基づくString
オブジェクトのsearch
メソッド"rajarao"
-
Symbol.search
オブジェクトのsearch
メソッド内で、Symbol.search
オブジェクトのSymbol.search
メソッドが呼び出されます(つまり、検索操作の実行はSymbol.search
オブジェクトに委任されます)。 文字列"rajarao"
このメソッドに渡されます。 この呼び出しを図式的に表すと、次のようになります。"rao"[Symbol.search]("rajarao")
-
"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行で「検索」すると、次のアクションが実行されます。
- コマンド
'barsoap'.search(soapObj);
文字シーケンス"barsoap"
String
オブジェクトに変換されます(new String("barsoap")
) -
soapObj
すでにオブジェクトであるため、変換されません -
"barsoap"
文字列に基づくString
オブジェクトのsearch
メソッド"barsoap"
- このメソッド内で、
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
と呼ばれます。
これらは規則です:
- メインのオブジェクト/クラスはいくつかのデータを保存する必要があります。
- 3〜6節で説明されているメソッドを実装する既知の
Symbol.iterator
シンボルであるプロパティが必要です。
-
Symbol.iterator
メソッドは、別のオブジェクト-イテレータを返す必要があります。
- 反復子には
next
メソッドが必要です。 -
next
方法では、段落1で説明したデータにアクセスする必要があります。
-
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.
, , , - (generator), .
.
- - ,
*<myGenerator>
. -function * myGenerator(){}
-
myGenerator()
generator
, () , , ,iterator
. -
yield
. -
yield
, . -
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); });
-
co
, , -
Post.findByID(10)
-
Post.findByID(10)
- , ,
.next(result)
-
post
-
post.getComments()
-
post.getComments()
- , ,
.next(result)
-
comments
-
console.log(post, comments);
async/await.
async/await
, , , , ,
co
. , — , ECMAScript , .
async
await
.
async/await.
- async/await
await
yield
. -
await
. -
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
, .
.
▍
-
.next()
{value: 'some val', done: false}
-
: 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, , , . .
- , . , , , ,
Object.keys
for-in
.
- — JavaScript, .
- — , . ,
for-of
.
- — , ,
.next()
. .
- — , . , , , , — async/await.
- async/await , .
- — ES2018, . , , , .
親愛なる読者! , , ?