非同期プログラミングによって引き起こされる問題は、クライアント側 Javascript では明らかではありませんが、サーバー側 Javascript がますます広く使用されるようになり、多数の非同期 IO 操作によってこの問題が明らかになります。この問題を解決するにはさまざまな方法があり、この記事ではその一部について説明しますが、詳しくは説明しません。誰もが自分の状況に応じて、自分に合った方法を選択する必要があります。
この記事では、js による非同期プログラミングについて詳しく紹介します。具体的な内容は次のとおりです。
1 非同期イベントについて
イベントは JavaScript の最も重要な機能であり、nodejs は js の非同期の性質を利用するように設計されています。ここでイベントのメカニズムについて説明しましょう。
js ファイルで特定の関数を実行する場合、foo() などの関数を直接呼び出す方法と、イベントを使用して関数を実行する方法があります。 setTimeout 関数や onready 属性に渡すなど、コールバック関数を呼び出します。
1. setTimeout 関数のイベントは非同期です
setTimeout は本質的に非同期イベントであり、遅延時間が経過するとトリガーされますが、場合によっては (実際にはほとんどの場合)、指定された遅延時間に従って実行されません。以下のコード
var start = new Date(); setTimeout(function() { console.log('settimeout1:',new Date()-start); }, 500); while (new Date() - start < 1000) { console.log('in while'); } document.getElementById('test').addEventListener('click', function(){ console.log('test:',new Date()-start); }, false) for(var i=0;i<10000;i++){ console.log('in for'); } setTimeout(function(){ console.log('settimeout2: ',new Date()-start); },1000); /* 10214 in while index.jsp (第 19 行) 10000 in for index.jsp (第 25 行) settimeout1: 2263 index.jsp (第 16 行) settimeout2: 3239 index.jsp (第 28 行) test: 10006 index.jsp (第 22 行) test: 28175 index.jsp (第 22 行) test: 28791 index.jsp (第 22 行) test: 28966 index.jsp (第 22 行) */
通常の理解では、遅延関数は 500 ミリ秒後に while ループを中断するはずですが、実際には中断されません。また、while ループおよび for ループ中に div をクリックしても、テストはすぐには出力されませんでした。説明は次のとおりです:
a) イベントキュー。 setTimeout 関数が呼び出されると、渡されたコールバック関数がイベント キューに追加され (イベントは初期化されてメモリ内にあります)、その後、コードが実行できなくなるまで後続のコードが実行され続けます (通常の実行フローではない) (イベント関数などの非同期コンテンツを除く)、適切なイベントがイベント キューからポップアウトされて実行されます。
b) js はシングルスレッドであり、スレッドがアイドル状態になるまでイベント ハンドラーは実行されません。
2 通常のイベントの非同期性は setTimeout
に似ています。
2 つの Promise オブジェクトと deferred オブジェクト
1.約束
Promise は、ajax などの非同期プログラミングにおける入れ子になったコールバック関数が多すぎると、コードがわかりにくくなり、特に nodejs では非同期が多用される問題の解決策です。さまざまなフレームワークが Promise を実装します。以下は jquery の Promise API です。
Promise の実装原則についてはここでは説明しません。この原則については別の章で説明します。
従来の Ajax 非同期プログラミングは次のように記述されます (jquery1.5 より前):
$.get('url', function(){ $.get('url1', function(){ $.get('url2', function(){ }, 'json'); }, 'json'); }, 'json');
このようなコードを書くと、開発と保守に大きな困難が生じます。幸いなことに、jquery1.5 が Promise を導入した後は、次のように書くことができます。
$.ajax( "example.php" ) .done(function() { alert("success"); }) .fail(function() { alert("error"); }) .always(function() { alert("complete"); });
見た目は明らかにずっとシンプルになりました。
2.遅延オブジェクト
var nanowrimoing = $.Deferred(); var wordGoal = 5000; nanowrimoing.progress(function(wordCount) { var percentComplete = Math.floor(wordCount / wordGoal * 100); $('#indicator').text(percentComplete + '% complete'); }); nanowrimoing.done(function(){ $('#indicator').text('Good job!'); });
3. ワーカー オブジェクトとマルチスレッド
4. 非同期スクリプトの読み込み
1. ページ内の従来のスクリプトの位置
スクリプトは、ブロッキングとノンブロッキングの 2 つの大きなカテゴリに分類されます。ここでのブロッキングは、実行ブロッキングではなく、ロードブロッキングを指します。
<!DOCTYPE html> <html> <head> <script src="headScript"></script> <script defer src="deferredScript"></script> </head> <body> <script async defer src="chatWidget"></script> <script async defer src="asyncScript"></script> </body> </html>
コードの上記の部分は、ページ内のスクリプトの位置に関して比較的標準的なものです。 1. 従来の未変更の headScript は、ブラウザーが JavaScript を上から下に解釈して実行するため、この一部のスクリプト ファイルはブロックされます。が最初に実行され、実行が完了するまで DOM はレンダリングされませんが、head タグ内の CSS が読み込まれます。 2. defer 属性を持つスクリプトは DOM がレンダリングされると同時にロードされますが、残念ながら、すべてのブラウザーが defer 属性をサポートしているわけではないため、jquery (関数) が作成されます。 。 3. async 属性と defer 属性の両方が存在する場合、defer は async をオーバーライドしますが、async が単独で提供される場合、スクリプトは DOM レンダリング中にロードされて実行されます。
2. プログラム可能なスクリプトの読み込み
最初から js ファイルをページに導入せず、ユーザーの操作を通じて動的に js スクリプトを読み込む場合は、それらをプログラムで追加できます。
ブラウザがサーバー スクリプトを取得するには 2 つの方法があります。もう 1 つは、ブラウザがサポートするため、DOM に