この記事では、主に JavaScript キュー関数と非同期実行の関連情報を詳しく紹介します。興味のある方は参考にしてください。
編集者注: 他の人の JavaScript コードをレビューしているときに、同様のキューを見たことがあります。関数を理解していますが、これは関数が順番に呼び出されることを保証するためであることがわかりました。この記事を読んで、非同期実行などにも使えることが分かりました。
順番に呼び出す必要があるいくつかの関数 fn1、fn2、fn3 があるとします。もちろん、最も簡単な方法は次のとおりです。ただし、これらの関数は実行時に 1 つずつ追加され、この時点でどのような関数があるかわからない場合は、関数を追加するときに配列を事前に定義しておいて、配列から順番に関数を取り出して順番に呼び出すことができます。 :
fn1(); fn2(); fn3();
このように、関数に名前があるかどうかは関係なく、
匿名関数
var stack = []; // 执行其他操作,定义fn1 stack.push(fn1); // 执行其他操作,定义fn2、fn3 stack.push(fn2, fn3); // 调用的时候 stack.forEach(function(fn) { fn() });
この実装は今のところうまく機能していますが、非同期関数の呼び出しという 1 つの状況を無視しました。非同期は JavaScript では避けられないトピックですが、ここでは JavaScript の非同期に関連するさまざまな用語や概念については説明しません (有名な解説など)。次のコードが 1、3、2 を出力することがわかっている場合は、読み続けてください:
var stack = []; function fn1() { console.log('第一个调用'); } stack.push(fn1); function fn2() { console.log('第二个调用'); } stack.push(fn2, function() { console.log('第三个调用') }); stack.forEach(function(fn) { fn() }); // 按顺序输出'第一个调用'、'第二个调用'、'第三个调用'
同様の非同期関数である関数がスタック キューにある場合、実装はめちゃくちゃになる:
console.log(1); setTimeout(function() { console.log(2); }, 0); console.log(3);
問題は明らかで、fn2は確かに順番に呼び出されますが、setTimeout内の関数fn2Timeout() { console.log('Second call') } はすぐには実行されません(タイムアウトを 0 に設定しても、fn2 は呼び出し直後に戻り、fn3 が実行された後、実際には fn2Timeout の番になります。
どうやって解決しますか?ここで重要なのは、fn2Timeout です。fn3 を呼び出す前に、実際に実行されるまで待つ必要があります。理想的には、次のようになります。ただし、これは、元の fn2Timeout を削除することと同じです。完全に新しい関数に変更し、元の fn2Timeout と fn3 を挿入します。元の機能を動的に変更するこの方法には、モンキー パッチと呼ばれる特別な用語があります。当社のプログラマーの信条によれば、「必ず実行できる」ですが、書くのは少しぎこちなく、自分自身で取り組むのは簡単です。もっと良い方法はありますか?
一歩下がって、fn3 を実行する前に fn2Timeout が完全に実行されるのを待つ必要はなく、代わりに fn2Timeout 関数本体の最後の行で呼び出します。 、しかし、fn2の定義 当時はfn3はありませんでしたが、このfn3はどこから来たのでしょうか?
fn3 を fn2 で呼び出す必要があるため、stack.forEach を通じて fn3 を呼び出すことができません。そうしないと、fn3 が 2 回呼び出されることになります。
var stack = []; function fn1() { console.log('第一个调用') }; stack.push(fn1); function fn2() { setTimeout(function fn2Timeout() { console.log('第二个调用'); }, 0); } stack.push(fn2, function() { console.log('第三个调用') }); stack.forEach(function(fn) { fn() }); // 输出'第一个调用'、'第三个调用'、'第二个调用'
function fn2() { setTimeout(function() { fn2Timeout(); fn3(); }, 0); }
next は stack[index] を使用してスタック内の関数を取得します。 next が呼び出されるたびにインデックスが 1 ずつ増加し、これにより、次の機能。
function fn2() { setTimeout(function fn2Timeout() { console.log('第二个调用'); fn3(); // 注{1} }, 0); }
stack.forEach 行が削除されたので、自分で next を呼び出します。Next は、実行するスタック内の最初の関数 fn1 を見つけて、next を呼び出します。 fn1 で次の関数 fn2 を見つけて実行し、fn2 で next を呼び出します。
関数キューのこの実装を理解した後、次のインタビューの質問を解決できるはずです:
function fn2() { setTimeout(function fn2Timeout() { console.log('第二个调用'); next(); }, 0); }
有名なconnect
フレームワーク
中央の部分
行列。ご興味がございましたら、ソースコードまたはこの説明「接続ミドルウェアとは」をご覧ください。
注意して見ると、当面はこれを関数の最後にのみ配置できることがわかりますが、これを中間に配置した場合、元の問題が引き続き発生します:
var index = 0; function next() { var fn = stack[index]; index = index + 1; // 其实也可以用shift 把fn 拿出来 if (typeof fn === 'function') fn(); }
redux と koa は実装が異なりますが、関数の途中に next を配置し、後続の関数を実行した後に戻って next 以下のコードを実行できます。これは非常に賢い方法です。時間があるときにまた書きます。
以上がこの記事の全内容です。皆様の学習に役立つことを願っています。また、皆様も Script Home をサポートしていただければ幸いです。
以上がJavaScriptのキュー関数と非同期実行について詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。