非同期プログラミングの利点と難点と解決策

21347 ワード

非ステップ:簡単に一つの任務を二つの段階に分けて、まず第一段を実行して、他の任務を実行します.準備ができたら、また第二段を実行しすぎます.
非同期と非閉塞は二つの異なる概念である.
非同期I/Oと非閉塞I/Oの違い:
ブロックによってCPUはI/Oを待ち、待ち時間を無駄にし、ブロックI/OとブロックI/Oの違いは呼び出し直後に戻ります.
渋滞ではない問題は、完全なI/Oが完了していないため、すぐに戻ってくるのは、ビジネスの期待のデータではなく、現在の呼び出しの状態だけです.完全なデータを得るためには、I/Oの繰り返し呼び出しが必要です.完了するかどうかは、非同期I/Oで実現できます.
利点:
イベント駆動の非ブロッキングI/Oモデルに基づいた特性であり、非ブロッキングI/Oは、CPUとI/Oを互いに依存しないように待機させることができます.
難点:
1.異常処理
  異常処理の約束、異常をリ掉関数の最初のパラメータとして返します.空なら異常がないと説明します.
2.関数の入れ子が深すぎます.
3.ブロッキングコード
 sleepの関数がないので、setTimeout()しか使えません.
4.マルチスレッドプログラミング
ブラウザマルチスレッドWeb Workers,nodejsのワークスレッドchild_processはその基本APIです.
5.非同期
異常プログラミング解決策
0.コールバック関数
Javascript言語の非同期プログラミングの実現はコールバック関数です.リ掉関数とは、タスクの第二段を単独で一つの関数に書いて、このタスクを再実行するときに直接にこの関数を呼び出します.
fs.readFile('/etc/passwd', function (err, data) {
    if (err) throw err;
    console.log(data);
});
readFile関数は、コールバック関数であり、リターン関数の最初のパラメータはエラーオブジェクトerrである必要があります.その理由は、プログラムは2つのセグメントに分けられています.2つのセグメントの間で投げられた異常プログラムは捕捉できません.パラメータとしてのみ第2のセグメントに入ることができます.
何度も繰り返すと悪魔のピラミッド問題になります.
1.Promise/Deferredモード
Promiseは多重ネストコールコール問題を解決するために持ち出したのです.新しい文法機能ではなく、新しい書き方です.
Deferredは主に非同期モデルを維持するための内部の状態である.Promiseは外部に作用して、then()の方法で外部に暴露してユーザー定義のロジックを追加します.
Promise操作は3つの状態しかありません.未完成状態、完成状態.  |--- 失敗状態
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);
    });
各.then()方法はいずれも新しいpromiseを返します.
fs-readfile-promiseモジュールを呼び出して、その役割はPromiseバージョンのreadFile関数を返すことです.then方法を提供します.ダウン関数をロードして、catch方法は実行中に投げたエラーを捕捉します.
promiseの最大の問題はコードの冗長性で、本来の任務はpromiseに包装されています.どんな操作でもいっぱいのthenです.元の意味が分かりません.
2.イベントのリリース/購読モード
  は、コールバック関数のイベント化です.Node自身が提供するeventsモジュールは、リリース/購読モードの簡単な実現である.
  例えば、イベントキューを利用して雪崩問題を解決することができる.
var proxy=new events.EventEmitter();
var status="ready";
var select=function(callback){
    proxy.once("selected",callback);
    if(status==="ready"){
        status="pending";
        db.select("SQL",function(results){
            proxy.emit("selected",results);
            status="ready";
        });
    }
}
3.ゲナート関数
協程:複数スレッドが互いに協力し、非同期タスクを完成する.大体の流れは以下の通りです
-第1ステップ、ワークAから実行開始
-第二ステップ、協働Aは半分まで実行し、一時停止に入り、実行権は協働路Bに移行する.
-第三ステップ(一定期間後)協働B交還実行権
-第四ステップ、協働A回復実行
協程はyield命令に遭遇したら一時停止し、実行権が戻ってきたら、再度一時停止のところから引き続き実行します.
全体のGenerator関数はパッケージの非同期タスク、または非同期タスクのコンテナです.
非同期タスクのパッケージ
var fetch = require('node-fetch');

function* gen(){
    var url = 'https://api.github.com/users/github';
    var result = yield fetch(url);
    console.log(result.bio);
}
Generator関数は非同期動作をカプセル化した.このコードは同期操作に似ています.yieldコマンドを加えました.
var g = gen();
var result = g.next();

result.value.then(function(data){
    return data.json();
}).then(function(data){
    g.next(data);
});
は、まずGenerator関数を実行し、エルゴードオブジェクトを取得し、その後、next方法を実行し、タスクの第1段階を実行する.FetchモジュールはPromiseオブジェクトに戻るので、thenメソッドで次のnextメソッドを呼び出します.
Thunk関数
JavaScript言語は、伝値呼び出しであり、そのThunk関数は、多パラメータ関数に置き換えられ、単一パラメータのバージョンに置き換えられ、また、引数としては戻り関数のみを受け取ります.
高次関数により実現した.
//     readfile(     )
fs.readFile(fileName,callback);

//Thunk   readFile(     )
var readFileThunk=Thunk(fileName);
readFileThunk(callback);

var Thunk=function(fileName){
    return function(callback){
        return fs.readFile(fileName,callback);
    }
}
簡単なThunk関数変換器
var Thunk = function(fn){
    return function (){
        var args = Array.prototype.slice.call(arguments);
        return function (callback){
            args.push(callback);
            return fn.apply(this, args);
        }
    };
};
変換器の使用
var readFileThunk = Thunk(fs.readFile);
readFileThunk(fileA)(callback);
ですが、生産環境で使うべきです.
Thunkifyモジュール
Generator関数の流れ管理
var fs = require('fs');
var thunkify = require('thunkify');
var readFile = thunkify(fs.readFile);

var gen = function* (){
    var r1 =  yield readFile('/etc/fstab');
    console.log(r1.toString());
    var r2 = yield  readFile('/etc/shells');
    console.log(r2.toString());
}
yieldコマンドは、プログラムの実行権をGenerator関数から移動するために使用され、実行権をGenerator関数に返す方法が必要である.
この方法はThunk関数です.フィードバック関数で実行権をGenerator関数に渡すことができます.自分で先に手動で上のGenerator関数を実行します.
var g = gen();

var r1=g.next();
//      ,        
r1.value(function(err,data){
    if(err) throw err;
    var r2=g.next(data);
    r2.value(function(err,data){
       if(err) throw err;
        g.next(data);
    });
});
は、同じコールバック関数を、nextメソッドに繰り返し入力するvalue属性である.再帰的にこのプロセスを自動的に完成させることができます.
以下の関数は簡単なGeneratorアクチュエータです.
//     
function run(fn) {
    //     
    var gen = fn();
    //       
    function next(err, data) {
        //  yield   value      data   Generator     yield    
        var result = gen.next(data);
        if (result.done) return;
        //         
        result.value(next);
    }
    //    
    next();
}
//    Generator  
run(gen);
は、いくつかの非同期的な操作があっても、直接run関数に入力すれば良い.もちろん、前提は各非同期操作で、Thunk関数ということです.
yield命令の後に付いているのはThunk関数でなければなりません.
coモジュールの原理
Generator関数が自動的に実行するには、非同期動作が結果を得たときに自動的に実行権を返す仕組みが必要です.
二つの方法はこの点ができます.
-1コールバック関数.非同期操作をThunk関数に近く包装し、リターン関数に実行権を渡す.
-2 Promiseオブジェクトです.非同期操作をPromiseの対象として包装し、then方法で実行権を渡す.
プロミセオブジェクトにパッケージ化する方法を説明します.
var fs = require('fs');
//       promise  
var readFile = function(fileName){
    return new Promise(function(resolve,reject){
        fs.readFile(fileName,function(error,data){
            if(error) reject(error);
            resolve(data);
        });
    });
};

var gen = function* (){
    var r1 =  yield readFile('/etc/fstab');
    var r2 = yield  readFile('/etc/shells');
    console.log(r1.toString());
    console.log(r2.toString());
}
上のGenerator関数を手動で実行します.
var g = gen();

g.next().value.then(function(data){
    g.next().value.then(function(data){
        g.next(data);
    });
});
は手動で実行するためのthen方法であり、階層的に関数を取り返す.自動アクチュエータを書くことができます.
//     
function run(gen){
    //     
    var g = gen();
    //       
    function next(data){
        //  yield   value      data   Generator     yield    
        var result=g.next(data);
        if(result.done) return result.value();
        //         
        result.value.then(function(data){
            next(data);
        });
    }
    //    
    next();
}
//    Generator  
run(gen);
4.フロー制御ライブラリ
  1.テールトリガと次のxt
  2.async
  3.Step
  4.ウィンド
参考:http://es6.ruanyifeng.com/#docs/async      《深入浅出nodejs》