JavaScript非同期プログラミングの5つの方法

5371 ワード

「非同期」とは、簡単にいうと、一つのタスクを二つの段階に分けて、まず第一段を実行し、他のタスクを実行し、第一段が実行結果が出たら、次に第二段を実行します.JavaScriptは非同期プログラムを採用する理由は二つあります.一つはJavaScriptは単一スレッドで、もう一つはCPUの利用率を高めるためです.CPUの利用率を向上させるとともに、開発の難しさ、特にコードの可読性を向上させました.
1.コールバック関数
2つの関数f 1とf 2があると仮定し、前者の実行結果を待つ.f 1()f 2()
f 1が時間がかかるタスクであれば、f 1を書き換え、f 2をf 1のコールバック関数として書くことが考えられます.
  function f1(callback){

    setTimeout(function () {

      // f1     

      callback();

    }, 1000);

  };
実行コードは以下のようになります.
このようにして同期動作を非同期動作に変更し、f 1はプログラムの起動を滞らせず、プログラムを先に実行する主要な論理に相当し、時間がかかる操作を実行を遅らせる.長所と短所:長所:コールバック関数の長所は簡単で分かりやすく、展開ができます.短所:コードの読み取りとメンテナンスに不利で、各部分間の高度結合(Couplling)は、流れが混乱します.また、タスクごとに1つのコールバック関数しか指定できません.コールバック地獄が現れます.
2.事件の傍受
もう一つの考えはイベント駆動モードを採用することです.タスクの実行はコードの順序に依存せず、あるイベントが発生するかどうかに依存します.
それともf 1とf 2を例にしますか?まず、f 1にイベントを結びつける(ここで使うjQueryの書き方).
f 1.on(‘done’,f 2);
上の行のコードの意味は、f 1がdoneイベントが発生したらf 2を実行するということです.そして、f 1を書き換えます.
function f 1(){
setTimeout(function(){
//f 1のタスクコード
f 1.trigger(‘done’)
}1000);
)
f 1.trigger(「done」)は、実行が完了したら、直ちにdoneイベントをトリガし、f 2の実行を開始することを表します.
この方法の利点は、複数のイベントを結びつけることができ、各イベントは複数のコールバック関数を指定することができ、かつ、「結合することができます」(Decoupling)ことができ、モジュール化を容易にすることである.欠点はプログラム全体がイベント駆動型になり、動作フローが非常に不明瞭になります.
3.リリース/購読モード
前の「事件」は、完全に「信号」と理解されます.
私たちは「信号センター」が存在すると仮定して、あるタスクの実行が完了したら、信号センターに「信号センター」に信号を発信し、他のタスクは信号センターに購読できます.これは「公開/購読モード」と呼ばれ、また「観察者モード」とも呼ばれています.
このモードは様々な実装があり、以下はBen AlmanのTinPub/Subを採用しています.これはjQueryのプラグインです.
まず、f 2は「信号センター」jQueryに購読します.「done」信号です.
jQuery.subscribe(「done」,f 2);
そして、f 1は次のように書き換えられる.
function f 1(){
setTimeout(function(){
//f 1のタスクコード
jQuery.publish(「done」);
}1000);
)
jQuery.publish(「done」)は、f 1の実行が完了したら、「信号センター」jQueryに「done」信号を発信し、f 2の実行を誘発するという意味です.
また、f 2の実行が完了したら、購読をキャンセルすることもできます.
jQuery.unsubscribe(「done」、f 2);
この方法の性質は”イベント傍受”と類似しているが,後者より明らかに優れている.「メッセージセンター」を見ることによって、どのぐらいの信号があるか、どのぐらいの受信者がいるかを知ることができますので、プログラムの実行を監視します.
4.Promise
PromisesオブジェクトはCommonJS作業グループが提案した仕様で、非同期プログラミングのために統一インターフェースを提供することを目的としています.簡単に言えば、各非同期タスクはPromiseオブジェクトに戻り、オブジェクトにはthenメソッドがあり、コールバック関数の指定が可能です.例えば、f 1のコールバック関数f 2は、次のように書くことができます.
f 1().then(f 2);
f 1は以下のように書き換えます.
function f 1(){
var dfd=$Deferred();
setTimeout(function(){
//f 1のタスクコード
dfd.resolive();
}500);
return dfd.promise;
)
このように書く利点は、コールバック関数がチェーン式の書き方になり、プログラムの流れがよく見えます.そしてセットの方法があり、多くの強力な機能を実現できます.
例えば、複数のコールバック関数を指定します.
f 1().then(f 2).then(f 3)
また例えば、エラーが発生した場合のコールバック関数を指定します.
f 1().then(f 2).fail(f 3);
また、前の3つの方法にはない利点があります.タスクが完了したら、再度コールバック関数を追加してください.このコールバック関数はすぐに実行されます.だから、ある事件や信号を逃したかどうか心配しなくてもいいです.この方法の欠点は編纂と理解で、すべて比較的に難しいです.しかし、Promiseは論理的なコールバック関数には適用されません.
5.Generatorとasync/await
Generatorは非同期を簡単に処理でき、本当にカルバーの存在を消滅させました.
//    tj/co    generator
co(function *() {
  try {
    const aResult = yield new Promise(/* getResultFromAPromise */)
    const bResult = yield new Promise(/* getResultFromBProimse */)
    const cResult = yield new Promise(/* getResultFromCPromise */)
    // do something
  } catch (err) {
    throw err
  }
})
generatorはもう使いやすいと思いますが、generatorで異歩を処理するにはtj/coが欠かせません.そしていくつかのピットさんbugと互換性の問題があります.次はasync/awaitを見ます.
async function () {
  try {
    const aResult = await new Promise(/* getResultFromAPromise */)
    const bResult = await new Promise(/* getResultFromBProimse */)
    const cResult = await new Promise(/* getResultFromCPromise */)
    // do something
  } catch (err) {
    throw err
  }
}
全体的にasync/awaitはcoライブラリを使ったゲナートと似ているように見えますが、とにかくcalbackはありません.コード構造はまた私たちがよく知っている美しい「シーケンス構造」に戻りました.
6.参考文書
  • Javascript非同期プログラミングの4つの方法
  • 最終回JavaScript非同期プログラミング
  • について話します.
  • Javascript非同期プログラミング