ホームページ  >  記事  >  ウェブフロントエンド  >  NodeJ の同時および非同期コールバックの詳細な分析 process_node.js

NodeJ の同時および非同期コールバックの詳細な分析 process_node.js

WBOY
WBOYオリジナル
2016-05-16 15:24:121382ブラウズ

同時と非同期というのは正確ではありません。連続的非同期と言うべきです。 NodeJs のシングルスレッド非同期機能により、複数の非同期操作が同時に実行されると、コールバックが最終的な実行結果を決定できなくなります。簡単な例を挙げてください:

for(var i = 0; i < 5; i++) {
  fs.readFile('file', 'utf-8', function(error, data){});
} 

ファイルを連続して読み取るために 5 つの非同期操作を開始しました。これは非常に簡単です。すべての非同期操作が完了したことを確認するにはどうすればよいでしょうか。後続の操作はすべて実行された後でのみ実行できるためです。ある程度経験のある学生であれば数え方を考えると思いますが、どうやって正確に数えるかはまた別の問題です。よく考えてください:

コールバックは、非同期操作が行われるたびにカウンターに 1 を加算し、非同期操作が終了するたびにカウンターを 0 にするかどうかを判断する関数です。このロジックは非常に単純で、実行時間とコールバック時間に関連するグローバル変数をカウンターとして必要とし、非同期メソッドに渡されたときに +1 演算を実行してからコールバック用の関数を返す必要がありますが、これは少し複雑です。ただし、「Js 関数の高度な使用法を参照してください:
」を参照してください。

var pending = (function() {
  var count = 0;
  return function() {
    count++;
    return function() {
      count--;
      if (count === 0) {
        // 全部执行完毕
      }
    }
  }
}); 

pending が呼び出されると、pending() になります。例:

var done = pending(); 

この時、カウント変数countは0に初期化され、返された関数はdone()がこの時に実行されるとどうなるでしょうか? pending によって返された最初の関数、つまり pending()() を直接実行することですか? まず、カウント変数 count+1 が返され、この関数が として直接渡されます。非同期メソッドへのコールバック。このコールバックを実行するときは、まずカウント変数 count-1 を設定し、次にカウントが 0 かどうかを判断します。0 の場合は、すべての非同期実行が完了したことを意味するため、連続した非同期操作が実現されます。同じコールバック。

鍵は 2 つのリターンにあります:

最初の戻り関数は count+1 で、その後コールバックが必要な関数を返します

2 番目の return 関数は、コールバックが必要な関数です。実行されるとカウントが 1 され、すべての非同期実行が完了したかどうかを判断します。完了すると、
がコールバックされます。

複数のファイルを読み取るための非同期コールバックの実際の例を見てください:

var fileName = ['1.html', '2.html', '3.html'];
var done = pending(function(fileData) {
  console.log('done');
  console.log(fielData);
});
for(var i = 0; i < fileName.lenght; i++) {
  fs.readFile(fileName[i], 'utf-8', done(fileName[i]));
}

完了したものは、コールバックして実行するメソッドをラップするために保留中のメソッドを使用します。次に、保留中のメソッドを改善する必要があります。

var pending = (function(callback) {
  var count = 0;
  var returns = {};
  console.log(count);
  return function(key) {
    count++;
    console.log(count);
    return function(error, data) {
      count--;
      console.log(count);
      returns[key] = data;
      if (count === 0) {
        callback(returns);
      }
    }
  }
}); 
callback はコールバック関数です。var done = pending(callback) の場合、done は実際には戻り値の添字として使用できるパラメーターを持っているため、ループ本体では Inned( fileName[i])、ファイル名が渡されます。このdone()はcount+1を実行した後、非同期メソッドに渡すコールバック関数を返します。前述したように、このコールバック関数はcount変数に基づいて実行するかどうかを決定します。 . にファイルの内容を渡します。つまり、戻ります。さて、実行してみましょう。結果が正確に表示されると思います。


0

1
2
3
2
1
0
完了
{"1.html": "xxx"、"2.html": "xxx"、"3.html": "xxx"}

0-3 から 0 までのカウントと、コールバック関数の出力完了とファイルの内容から明らかです。


この問題は解決されました。そのようなメソッドをカプセル化して再利用する方法を考える必要があります。そうしないと、毎回保留を書くのは非科学的ではないでしょうか。


テンプレート解析のサブテンプレート操作に適用される UnJ (NodeJs ベースの Web 開発フレームワークの 1 つ) の処理メソッドを見てみましょう。


unjs.asyncSeries = function(task, func, callback) {
  var taskLen = task.length;
  if (taskLen <= 0) {
    return;
  }
  var done = unjs.pending(callback);
  for(var i = 0; i < taskLen; i++) {
    func(task[i], done);
  }
} 

asyncSeries には 3 つのパラメータがあります。つまり、

タスク: 読み取る必要があるファイルなど、処理する必要があるオブジェクト。リストです。リストでない場合、またはリストの長さが 0 の場合、実行されません。


func: fs.readFile などの非同期メソッドがそれを通じて渡されます


callback: コールバックするメソッド


done は先ほどと同様に func に渡しますが、実行はしません。パラメータはアプリケーション側で制御できれば良いので、アプリケーション側に実行させます。


サブテンプレートを扱うときの操作を見てください:


var subTemplate = [];
var patt = /\{\% include \'(.+)\' \%\}/ig;
while(sub = patt.exec(data)) {
  var subs = sub;
  subTemplate.push([subs[0], subs[1]]);
}
unjs.asyncSeries(subTemplate, function(item, callback) {
  fs.readFile('./template/' + item[1], 'utf-8', callback(item[0]));
}, function(data) {
  for(var key in data) {
    html = html.replace(key, data[key]);
  }
}); 

サブテンプレートのリストは、サブテンプレートの分析に基づいて生成されたデータであり、各サブ項目の最初の値はサブテンプレートの呼び出しテキスト、つまり {% です。 include 'header.html ' %} のような文字列の場合、2 番目のパラメータはサブテンプレート ファイル名、つまり header.html
です。

asyncSeries の 2 番目のパラメーターは callback ですが、これは実際には 3 番目のパラメーターであり、前述したように、asyncSeries 内では実行されていません。ここでは、つまり callback(item[0]) とパラメータを指定します。これは、後で親テンプレート内のサブテンプレートを呼び出す文字列が、このパラメータに基づいて対応するサブテンプレートのコンテンツに置き換えられるためです。

このように、継続的な非同期が必要な限り、asyncSeries メソッドを使用して処理できます。非同期関係のため、プログラムの流れが少し複雑で、慣れていても突然理解できない場合があります。 、2 番目のパラメータのコールバックは、実際には 3 番目のパラメータによって生成されます。このコールバックとは一体何なのか疑問に思われるかもしれません。また保留中の返品が 2 件ありますが、これは理解しにくいため、さらに検討する必要があります。

これで、Js 関数の高度な機能を使用して、継続的な非同期コールバックが完了しました。ただし、NodeJ の非同期の性質により、値の転送を必要とする継続的な非同期操作など、プログラムの制御が非常に問題になります。これらはすべて、このアイデアと変更によって実現できます。

上記の内容は、エディターが共有した NodeJ の同時および非同期コールバック処理に関する知識です。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。