ES 6前後の非同期プログラミングについて話してください.


詳細はクリックしてくださいhttp://blog.zhangbing.club/Ja...
Javascript言語の実行環境は「シングルスレッド」です.もしプログラムがないなら、まったく使えません.カードでなくてはいけません.
この問題を解決するために、Javascript言語はタスクの実行モードを二つに分けます.同期と非同期の2つのモード概念がよく分かります.
ES 6の誕生前に、非同期プログラミングの方法は、次の4つがあります.コールバック関数、イベントモニター、リリース/購読、Promiseオブジェクトです.
コールバック関数
これは非同期プログラミングの最も基本的な方法である.
2つの関数f 1とf 2があると仮定し、前者の実行結果を待つ.
  f1();
  f2();
f 1が時間がかかるタスクであれば、f 1を書き換え、f 2をf 1のコールバック関数として書くことが考えられます.
  function f1(callback){
    setTimeout(function () {
      // f1     
      callback();
    }, 1000);
  }
実行コードは以下のようになります.
f1(f2);
このようにして、同期動作を非同期操作に変えました.f 1はプログラムの実行を滞らせません.先にプログラムを実行する主要なロジックに相当します.時間がかかる操作を実行を遅らせます.
コールバック関数の利点は、単純で分かりやすく配置されており、欠点はコードの読み取りと維持に不利であり、各部分間の高度結合(Couplling)は、プロセスが混乱し、各タスクは一つのコールバック関数しか指定できない.
事件の傍受
もう一つの考えはイベント駆動モードを採用することです.タスクの実行はコードの順序に依存せず、あるイベントが発生するかどうかに依存します.
それともf 1とf 2を例にしますか?まず、f 1にイベントを結びつける(ここで使うjQueryの書き方).
f1.on('done', f2);
上の行のコードの意味は、f 1がdoneイベントが発生したらf 2を実行するということです.そして、f 1を書き換えます.
  function f1(){
    setTimeout(function () {
      // f1     
      f1.trigger('done');
    }, 1000);
  }
f 1.trigger('done')は、実行が完了したら、直ちにdoneイベントをトリガし、f 2の実行を開始することを示しています.
この方法の利点は、複数のイベントを結びつけることができ、各イベントは複数のコールバック関数を指定することができ、かつ「結合解除」(Decoupling)が可能であり、モジュール化を容易にすることができるということである.欠点はプログラム全体がイベント駆動型になり、動作フローが非常に不明瞭になります.
リリース/購読
前の節の「事件」は、完全に「信号」と理解できます.
私たちは、あるミッションを実行した「信号センター」があると仮定して、信号センターに信号を送ると、他のタスクは信号センターに「購読」(subscribe)という信号を送って、いつ自分が実行できるかを知ることができます.これは「公開/購読モード」と呼ばれ、また「観察者モード」とも呼ばれています.
このモードは様々な実装があり、以下はBen AlmanのTinPub/Subを採用しています.これはjQueryのプラグインです.
まず、f 2は「信号センター」jQueryに「done」信号を購読する.
jQuery.subscribe("done", f2);
そして、f 1は次のように書き換えられる.
  function f1(){
    setTimeout(function () {
      // f1     
      jQuery.publish("done");
    }, 1000);
  }
jQuery.publish(「done」)は、f 1の実行が完了したら、「信号センター」jQueryに「done」信号を送信し、f 2の実行を誘発するという意味です.
また、f 2の実行が完了したら、購読をキャンセルすることもできます.
jQuery.unsubscribe("done", f2);
この方法の性質は「イベントモニター」と類似しているが,後者より明らかに優れている.私たちは「メッセージセンター」を見ることによって、どのぐらいの信号があるか、どのぐらいの予約者がいるかを知ることができます.それによってプログラムの運行を監視します.
Promisesオブジェクト
PromisesオブジェクトはCommonJS作業グループが提案した仕様で、非同期プログラミングのために統一インターフェースを提供することを目的としています.
簡単に言えば、各非同期タスクはPromiseオブジェクトに戻り、オブジェクトにはthenメソッドがあり、コールバック関数の指定が可能です.例えば、f 1のコールバック関数f 2は、次のように書くことができます.
f1().then(f2);
f 1は以下のように書き換えます.
  function f1(){
    var dfd = $.Deferred();
    setTimeout(function () {
      // f1     
      dfd.resolve();
    }, 500);
    return dfd.promise;
  }
このように書く利点は、コールバック関数がチェーン式の書き方になり、プログラムの流れがよく見えます.そしてセットの方法があり、多くの強力な機能を実現できます.
例えば、複数のコールバック関数を指定します.
f1().then(f2).then(f3);
また例えば、エラーが発生した場合のコールバック関数を指定します.
f1().then(f2).fail(f3);
また、前の3つの方法にはない利点があります.タスクが完了したら、再度コールバック関数を追加してください.このコールバック関数はすぐに実行されます.だから、ある事件や信号を逃したかどうか心配しなくてもいいです.この方法の欠点は編纂と理解で、すべて比較的に難しいです.
ES 6の誕生後、Generator関数が現れ、JavaScriptの非同期プログラムを新たな段階に持ち込んだ.ES 6もPromiseを言語標準に書き、用法を統一し、原生はPromiseの対象を提供した.
ES 6非同期プログラミングの方法は、大体2つあります.Generator関数、Promise.
Generator関数
特徴:星番号付きfunction、yield文、next()は次のyield表現の中のyieldの値を取得して、エルゴードインターフェースを持って、for.ofと組み合わせて使うことができます.
以下のコードでは、Generator関数は、まずリモートインターフェースを読み取り、その後、JSON形式のデータ解析情報をパッケージ化する.このコードは同期操作に似ています.yieldコマンドを加えました.
var fetch = require('node-fetch');

function * gen() {
    var url = 'http://api.github.com/users/github';
    var result = yield fetch(url);
    console.log(result.bio);
}

var g = gen();
var result = g.next();

result.value.then(function(data) {
    return data.json();
}).then(function (data) {
    g.next(data);
});
実行プロセス:
まずGenerator関数を実行し、エルゴードオブジェクトを取得し、nextメソッド(2行目)を使用して、非同期タスクの第1段階を実行します.FetchモジュールはPromiseオブジェクトを返すので、thenメソッドで次のnextメソッドを呼び出します.
短所:
Generator関数は非同期的な動作を簡潔に表しているが、プロセス管理は不便である(すなわち、第一段階をいつ実行するか、第二段階をいつ実行するか)、すなわち自動化のプロセス管理はどのように実現されるかを見ることができる.
追加開拓
阮一峰のECMAScript 6入門を参考にして、Thunk関数で自動化プロセス管理を実現し、Generator関数を拡張します.前提は各非同期操作であれば、Thunk関数なら、価格はCOモジュールで自動化プロセス管理を実現します.coモジュールは二つの自動実行器(Thunk関数とPromiseオブジェクト)を一つのモジュールに包装します.coを使用する前提条件は、Generator関数のyield命令の後は、Thunk関数またはPromiseオブジェクトだけです.配列やオブジェクトのメンバーが全部Promiseオブジェクトであれば、coを使用することもできます.後に、ES 2017標準はasync関数を導入して、Generatorに対してさらに「文法アップグレード」します.async関数は何ですか?一言で言うと、それはGenerator関数の文法飴です.async関数はGenerator関数を改善し、以下の4点に反映されています.
  • は、アクチュエータを内蔵する.
  • Generator関数の実行はアクチュエータに依存しなければならないので、coモジュールがあります.async関数はアクチュエータを持っています.つまり、async関数の実行は、普通の関数と同じです.一行だけです.
  • より良い意味.
  • asyncとawaitは星号とyieldより意味がはっきりしました.asyncは関数に非同期動作があり、awaitは後に続く表現は結果を待つ必要があると表しています.
  • より広い適用性.
  • coモジュールは、yield命令の後はThunk関数またはPromiseオブジェクトだけとし、async関数のawaitコマンドの後はPromiseオブジェクトと元のタイプの値(数値、文字列とブール値は同じですが、この場合は同期操作と同じです)としています.
  • の戻り値はPromiseです.
  • async関数の戻り値はPromiseオブジェクトで、これはGenerator関数の戻り値よりもIteratorオブジェクトの方がずっと便利です.then方法で次のステップの操作を指定できます.さらに、async関数は完全に複数の非同期動作と見なされ、Promiseオブジェクトとして包装されていますが、awaitコマンドは内部thenコマンドのシンタックス飴です.
    Promise
    ES 6はPromiseオブジェクトがPromiseのインスタンスを生成するためのコンストラクタであると規定しています.
    次のコードはPromiseの例を作成します.
    const promise = new Promise(function(resolve, reject) {
      // ... some code
    
      if (/*        */){
        resolve(value);
      } else {
        reject(error);
      }
    });
    Promiseコンストラクタはパラメータとして関数を受け入れ,この関数の二つのパラメータはそれぞれreolveとrejectである.それらは2つの関数で、JavaScriptエンジンによって提供されます.自分で配置する必要はありません.
    Promiseのインスタンスが生成された後、then方法でそれぞれreolved状態とreject状態のコールバック関数を指定することができます.
    promise.then(function(value) {
      // success
    }, function(error) {
      // failure
    });
    then法はパラメータとして2つのコールバック関数を受け入れることができる.最初のコールバック関数はPromiseオブジェクトの状態がreolvedになったときに呼び出します.第二のコールバック関数はPromiseオブジェクトの状態がrejectになったときに呼び出します.このうち、第二の関数はオプションであり、必ずしも提供する必要はない.この2つの関数は、パラメータとしてPromiseオブジェクトから流れる値を受けます.Promiseの基本的な使い方はこれに言及して、もっと深く使用して、阮一峰のECMAScript 6入門を参照してください.
    特にES 6の前にプロミスは規範と原則であり、設計されたライブラリ複合規格の要求がプロミセであり、現在流行しているプロミセはqとwhen、RSV P.js、jQueryのDeferredなどがあります.ES 6の後、Promiseの多くの規範の中の一つを言語標準に書き込みます.ES 6のPromiseはその中の一つです.各Promise規範の間には細かい差異があります.(主に特性上の)
    ソースを参照:
  • ECMAScript 6入門
  • Javascript非同期プログラミングの4つの方法