ES6 - ジェネレーターと非同期関数

ここに画像の説明を挿入

I.はじめに

ES6 が誕生する前には、非同期プログラミングには大きく分けて 4 つの方法がありました。

  • 折り返し電話
  • イベントリスナー
  • 公開/購読
  • Promiseオブジェクト

回调函数それ自体には問題はありませんが、問題は、複数のコールバック関数のネストによってコールバック地獄が発生し、コードの保守とロジックの混乱にとって非常に好ましくないことです。

Promiseこの問題を解決するためにオブジェクトが提案されています。これは新しい文法上の機能ではなく、コールバック関数のネストをチェーン呼び出しに変更できる新しい記述方法です。Promiseを使って複数のファイルを連続して読み込む場合の書き込み方法は以下の通りです。

var readFile = require('fs-readfile-promise');
readFile(fileA)
.then(function (data) {
    
    
  console.log(data.toString());
})
.then(function () {
    
    
  return readFile(fileB);
})
.then(function (data) {
    
    
  console.log(data.toString());
})
.catch(function (err) {
    
    
  console.log(err);
});

Promise の記述方法はコールバック関数を改良しただけであることがわかりますが、then メソッドを使用すると非同期タスクの 2 段階の実行がより明確にわかるようになり、それ以外に新しい点はありません。

Promise の最大の問題はコードの冗長性であり、元のタスクが Promise によってラップされているため、どのような操作であっても、一見したところそれが束になっていて、元のセマンティクスが非常に不明確になります。

那么,有没有更好的写法呢?:

ジェネレーター関数は、JavaScript 非同期プログラミングをまったく新しいレベルに引き上げます。


2. はじめに

ジェネレーター機能は、非同期プログラミングを解決するために ES6 が提供するソリューションの 1 つです。

Generator 関数全体は、カプセル化された非同期タスク、または非同期タスクのコンテナーです。非同期操作を一時停止する必要がある場所は、yield ステートメントでマークされます。Generator関数の実行方法は以下のとおりです。

function* gen(x) {
    
    
  var y = yield x + 2;
  return y;
}

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

上記のコードでは、Generator 関数を呼び出すと内部ポインター (トラバーサー) g が返されます。これも、Generator 関数が通常の関数と異なる点です。つまり、Generator 関数を実行すると、結果ではなくポインター オブジェクトが返されます。ポインター g の next メソッドを呼び出すと、内部ポインター (つまり、非同期タスク実行の最初の段落) が移動し、最初に見つかった yield ステートメントを指します。上記の例は x + 2 まで実行されます。

つまり、次のメソッドの役割は、Generator 関数を段階的に実行することです。次のメソッドが呼び出されるたびに、現在のステージの情報 (value 属性と Done 属性) を表すオブジェクトが返されます。value 属性は、yield ステートメントの背後にある式の値で、現在のステージの値を示します。done 属性は、Generator 関数が実行されたかどうか、つまり次のステージがあるかどうかを示すブール値です。

3. 特徴

1.Generator関数を定義するには、関数の後に数字を追加する必要があります*

function* helloWorldGenerator(){
    
    ...}

2. 関数を呼び出しても関数データは出力されませんが、ポインター オブジェクトが返されます。

3. ポインタ オブジェクトの次のメソッドが呼び出されてジェネレータ関数の内容が実行されるたびに、返される結果はイテレータの結果と同様になります。


4番目、ジェネレーター関数の実装

Generator 関数によって返されるトラバーサー オブジェクトは、nextメソッドが呼び出された場合にのみ次の内部状態をトラバースできるため、実際には実行を一時停止できる関数を提供します。yield式は一時停止フラグです。

トラバーサオブジェクトのメソッドの動作ロジックnextは以下のとおりです。

(1)yield式が見つかった場合、後続の操作の実行は中断され、直後の式の値が返されyieldたオブジェクトのvalue属性値として使用されます。

(2) 次回nextメソッドが呼び出されたとき、次のyield式が見つかるまで実行を続けます。

(3) 新しいyield式が見つからない場合、関数はステートメントまで実行されreturnreturnステートメントの後の式の値がvalue返されたオブジェクトの属性値として使用されます。

(4) 関数にステートメントがない場合、return返されるオブジェクトのvalue属性値は次のようになります。undefined

次の例を参照してください

      function* helloWorldGenerator() {
    
    
        yield "hello";
        console.log("111");
        yield "world";
        console.log("222");
        return "ending";
      }
      var hw = helloWorldGenerator();
      console.log(hw.next());
      console.log(hw.next());
      console.log(hw.next());

操作結果:

{
    
    value: 'hello', done: false}
111
{
    
    value: 'world', done: false}
222
{
    
    value: 'ending', done: true}

つまり、次のようになります。

呼び出すたびに、next を使用して呼び出す必要があります。next を使用するたびに、yield を呼び出します。プログラムが yield にタッチすると、プログラムはブロック状態になり、ヒットするまで実行を続けます。次の次、収量。つまり、yield が呼び出されるたびに、yield が実行されます。

Generator 関数は yield 式を必要とせず、純粋に遅延実行関数になります。次のように:

   function* fun() {
    
    
    console.log("执行了!");
   }
   var generator = fun();
   generator.next();
   setTimeout(function () {
    
    
    generator.next();
   }, 2000);

上記のコードでは、関数 fun が通常の関数の場合、変数ジェネレーターに値が割り当てられたときに関数 fun が実行されます。ただし、関数 fun はジェネレーター関数であるため、関数 fun は次のメソッドが呼び出されたときにのみ実行されます。

さらに、yield 式は Generator 関数でのみ使用でき、他の場所で使用するとエラーが報告されることに注意してください。

五、非同期機能

async関数とは何ですか? 一言で言えば、 のGenerator 函数糖衣構文です。非同期操作がより便利になります。
これは、日々の開発における一般的な書き方でもあります。

1. Generator 関数は非同期を処理します。

readFile は非同期操作であり、何を行うかは関係ありません。

const gen = function* () {
    
    
  const f1 = yield readFile('/etc/fstab');
  const f2 = yield readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};

2、async関数の非同期処理

const asyncReadFile = async function () {
    
    
  const f1 = await readFile('/etc/fstab');
  const f2 = await readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};

比較すると、async 関数は Generator 関数のアスタリスク (*) を async に置き換え、yield を await に置き換えるだけであることがわかります。その最大の利点は、コードが同期操作と非常によく似て記述されていることです。yieldコマンドを削除しても、まったく同じになります。

Generator 関数への async 関数の改善は、次の 4 つの点に反映されています。

(1) アクチュエータを内蔵しています。

Generator 関数の実行では、nextメソッドを呼び出すか、co モジュールを使用して実際に実行して最終結果を取得する必要があります。
そしてasync函数自带执行器つまり、非同期関数の実行は通常の関数の実行とまったく同じで、行は 1 行だけです。

(2) セマンティクスの改善。

async和await、セマンティクスはアスタリスクや利回りよりも明確です。async は関数内に非同期操作があることを意味し、await は直後の式が結果を待つ必要があることを意味します。

(3) 適用範囲が広がります。

co モジュールは、yield コマンドの後にはサンク関数または Promise オブジェクトのみを続けることができると規定しています。これは、而async函数的await命令后面Promise オブジェクトとプリミティブ型の値 (数値、文字列、ブール値) にすることができますが、この時点では自動的に変換されます。すぐに解決される romise オブジェクトに変換されます)。

(4) 戻り値は Promise です。

async函数的返回值是 Promise 对象これは、Generator 関数の戻り値が Iterator オブジェクトであるよりもはるかに便利です。then メソッドを使用して、次のアクションを指定できます。

さらに、async函数これは Promise オブジェクトにパッケージ化された複数の非同期操作とみなすことができ、awaitコマンドは内部の then コマンドの構文糖となります。


【参考ドキュメント】:
1. Generator関数の構文: https://es6.ruanyifeng.com/#docs/generator
2. Async関数: https://es6.ruanyifeng.com/#docs/async

おすすめ

転載: blog.csdn.net/qq_43886365/article/details/132062626