この記事では主に Node 非同期プログラミングの仕組みを紹介します。編集者がそれを紹介し、参考にさせていただきます。編集者をフォローして見てみましょう。皆さんのお役に立てれば幸いです。
この記事では、Node 非同期プログラミングを紹介し、それを皆さんと共有します。詳細は次のとおりです。
非同期プログラミングの現在の主なソリューションは次のとおりです:
イベント パブリッシング/サブスクリプション モード
Promise/Deferred モード
プロセス制御ライブラリ
イベント発行/購読モード
ノード自体がイベントモジュールを提供し、イベントの発行/購読を簡単に実装できます
//订阅 emmiter.on("event1",function(message){ console.log(message); }) //发布 emmiter.emit("event1","I am mesaage!");
リスナーは柔軟に追加および削除でき、イベントと特定の処理ロジックを簡単に関連付けて分離できます
イベント パブリッシュ/サブスクライブ モデルは、ビジネス ロジックを分離するためによく使用されます。イベント発行者は、サブスクライブされたリスナーがビジネス ロジックを実装する方法や、リスナーの数に注意を払う必要はありません。リスナーが存在し、メッセージを通じて柔軟にデータを転送できます。
次の HTTP は典型的なアプリケーション シナリオです
var req = http.request(options,function(res){ res.on('data',function(chunk){ console.log('Body:'+ chunk); }) res.on('end',function(){ //TODO }) })
10 を超えるリスナーがイベントに追加される場合は、emmite.setMaxListeners(0) を呼び出すことで警告が表示されます
。イベントモジュールを継承します
var events = require('events'); function Stream(){ events.EventEmiiter.call(this); } util.inherits(Stream,events.EventEmitter);
イベントキューを使用して雪崩問題を解決します
いわゆる雪崩問題とは、アクセス量が多く同時実行数が多い条件下でのキャッシュ障害です。多くのリクエストが同時にデータベースに統合されると、データベースは同時にこのような大規模なクエリリクエストに耐えることができなくなり、ウェブサイト全体の応答速度にさらに影響を及ぼします。 解決策:
var proxy = new events.EventEmitter(); var status = "ready"; var seletc = function(callback){ proxy.once("selected",callback);//为每次请求订阅这个查询时间,推入事件回调函数队列 if(status === 'ready'){ status = 'pending';//设置状态为进行中以防止引起多次查询操作 db.select("SQL",function(results){ proxy.emit("selected",results); //查询操作完成后发布时间 status = 'ready';//重新定义为已准备状态 }) } }
複数の非同期イベント間の解決策
上記の状況は、リスナー間の関係は 1 対多ですが、非同期プログラミングでは、イベントとリスナーの間に多対 1 の状況も存在する可能性があります。
ここでは、ページのレンダリングに必要なテンプレートの読み取り、データの読み取り、およびローカライズされたリソースの読み取りを例として取り上げ、EventProxy モジュール ソリューションを簡単に紹介します
var count = 0 ; var results = {}; var done = function(key,value){ result[key] = value; count++; if(count === 3){ render(results); } } fs.readFile(template_path,"utf8",function(err,template){ done('template',template) }) db.query(sql,function(err,data){ done('data',data); }) l10n.get(function(err,resources){ done('resources',resources) })
でイベントを使用する場合上記の方法では、実行プロセスを事前に設定する必要があります。これは、パブリッシュ/サブスクライブ モードの動作メカニズムによって決定されます。
var after = function(times,callback){ var count = 0, result = {}; return function(key,value){ results[key] = value; count++; if(count === times){ callback(results); } } } var done = after(times,render); var emitter = new events.Emitter(); emitter.on('done',done); //一个侦听器 emitter.on('done',other); //如果业务增长,可以完成多对多的方案 fs.readFile(template_path,"utf8",function(err,template){ emitter.emit('done','template',template); }) db.query(sql,function(err,data){ emitter.emit('done','data',data); }) l10n.get(function(err,resources){ emitter.emit('done','resources',resources) })
では、非同期呼び出しを先に実行して配信処理を遅らせる方法はあるのでしょうか?次に説明するのは、この状況に対処する方法です。 Promise/Deferred パターン
Promise/APromise 操作は、未完了、完了、失敗の 3 つの状態のいずれかのみ。
Promiseの状態は、未完了状態から完了状態または失敗状態にのみ変換され、完了状態と失敗状態を相互に変換することはできません
。 Promise は変換されますが、変更することはできません。
Promise オブジェクトには then() のみが必要です
完了状態とエラー状態でコールバック メソッドを受け入れます
オプションで 3 番目のメソッドとして進捗イベント コールバックをサポートします
then() メソッドのみ関数オブジェクトを受け入れ、他のオブジェクトは無視されます
then() メソッドはチェーン呼び出しを実現するために Promise オブジェクトを返し続けます
Node のイベント モジュールを通じて Promise 実装をシミュレートします
var proxy = new EventProxy(); proxy.all('template','data','resources',function(template,data,resources){ //TODO }) fs.readFile(template_path,'utf8',function(err,template){ proxy.emit('template',template); }) db.query(sql,function(err,data){ proxy.emit('data',data); }) l10n.get(function(err,resources){ proxy.emit('resources',resources); })
$.get('/api',{ success:onSuccess, err:onError, complete:onComplete }) //需要严谨设置目标
var Promise = function(){ EventEmitter.call(this) } util.inherits(Promise,EventEmitter); Promise.prototype.then = function(fulfilledHandler,errHandler,progeressHandler){ if(typeof fulfilledHandler === 'function'){ this.once('success',fulfilledHandler); //实现监听对应事件 } if(typeof errorHandler === 'function'){ this.once('error',errorHandler) } if(typeof progressHandler === 'function'){ this.on('progress',progressHandler); } return this; }
var Deferred = function(){ this.state = 'unfulfilled'; this.promise = new Promise(); } Deferred.prototype.resolve = function(obj){ //当异步完成后可将resolve作为回调函数,触发相关事件 this.state = 'fulfilled'; this.promise.emit('success',obj); } Deferred.prototype.reject = function(err){ this.state = 'failed'; this.promise.emit('error',err); } Deferred.prototype.progress = function(data){ this.promise.emit('progress',data) }
Promise での複数の非同期コラボレーション
res.setEncoding('utf8'); res.on('data',function(chunk){ console.log("Body:" + chunk); }) res.on('end',function(){ //done }) res.on('error',function(err){ //error }
チェーン呼び出しを実装するようにコードを変換してみます
res.then(function(){ //done },function(err){ //error },function(chunk){ console.log('Body:' + chunk); })
関連する推奨事項:
Javascript での非同期プログラミングの 4 つの方法の紹介
非同期プログラミングの説明 es6 の Promise
以上がNode非同期プログラミング機構の詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。