非同期 javascript_javascript 手法の原理と実装手法の紹介

WBOY
リリース: 2016-05-16 17:48:38
オリジナル
1145 人が閲覧しました

仕事の都合上、Web ページ上にスクリプトを記述して、Web ページを通じてシステムにデータをバッチで送信する必要があります。そこで Greasemonkey プラグインを思いついて書き始めたところ、問題はスムーズに解決されました。しかし、脚本を要約して整理するとき、私はいつも自分自身にこう問いかけました。「もっとシンプルにできないだろうか?」
私の答えはもちろん「はい」です。

まず、データのバッチ送信に関する要件を確認します。システムに挿入するユーザー データのバッチがありますが、システム ライブラリのテーブル構造が決定的ではないため、挿入用の SQL ステートメントに変換できません。 。挿入するデータは 200 件近くあり、システムに手動で入力したとしても、おそらく 1 日かかります。プログラマーとしては、もちろんそんな愚かなことはしません、プログラムを使って解決する必要があります。このプログラミングプロセスには 1 日かかりました。手入力に比べて、このブログ記事からの副収入は絶対に費用対効果が高いです!

プログラミング プラットフォームを選択するのに時間はかかりませんでした。ブラウザはもちろん Firefox でした。スクリプトの作業プロセス:
スクリプトに挿入するデータを事前に保存します
マウスのクリックをシミュレートしてページ上に入力ウィンドウを開きます
入力ウィンドウにデータを入力し、クリックをシミュレートします「送信」ボタンをクリックして、システムに送信されたデータを送信します。
すべてのデータが処理されるまで順番にループします。

ここでの技術的な問題点は次のとおりです。
入力ウィンドウを開くには、ネットワークの状況に応じて不規則な時間待機する必要があります。
データをバックグラウンドに送信すると、次のデータに進む前に処理が完了するまで待つ必要があります。
私が初心者であれば、もちろん、次のようなアプリケーション ロジックを直接作成します。

コードをコピー コードは次のとおりです:

for(var i = 0; i < dataArray.length; i)
{ 3: clickButtonForInputWindow();
waitInputWindow(); (dataArray[i] );
clickSubmitButton();
waitInputWindowClose();
}

実際には、数分後にすべてのブラウザが表示されます。 「応答なし」と表示され強制終了されました。その理由は、ブラウザが JavaScript を呼び出すと、CPU が実行のために js に渡され、インターフェイス メッセージを処理する時間がなくなるため、メイン インターフェイスが応答を停止するためです。

「ロックなし」の要件を満たすために、次のようにスクリプトを変更できます:

コードをコピー コードは次のとおりです:
for(var i = 0; i < dataArray.length; i)
{
setTimeout(clickButtonForInputWindow); 🎜>setTimeout(waitInputWindowClose );
}


実際、ブラウザがサポートできる非同期操作は setTimeout と setInterval だけです。これら 2 つの関数をよりエレガントに使用して非同期操作を実装するにはどうすればよいでしょうか?現在の単純な答えは、Lao Zhao の Wind.js です。この関数ライブラリを使用したことはありませんが、$await 呼び出しだけで、簡潔さに対する一貫した要件を満たしています。しかし、私のような単一ファイルのスクリプトの場合、インターネットから外部 js ライブラリをダウンロードすることは、非同期操作をサポートするコードをコピーすることほど速くも楽しくもないことは明らかです。
そこで、別の方法を見つけて、コンパイルが不要で、より使いやすく、コピー&ペーストで使える非同期関数ライブラリを作成することにしました。

非同期について説明する前に、同期操作のいくつかの構造タイプを思い出してみましょう。

シーケンス: ステートメントが実行される順序です。
判定: 判定ステートメントです。
ループ: strict ジャンプ(goto)すべきですが、現代の言語の多くはgotoをキャンセルしています。ループは実際には、if と goto を組み合わせた複合構造である必要があります。
非同期操作の難しさは 2 つの場所にあります。

非同期の判断: 非同期状況での判断は、基本的に、条件が満たされていることを検出し、特定のアクションを実行することです。
非同期シーケンス: シーケンスの各ステップの後、制御が戻り、次のタイム スライスで次のステップが待機されます。難しいのは秩序を維持することです。特に、2 つの連続したアクションの間に非同期ループがある場合に顕著です。
非同期ループ: 各ループの後、制御がブラウザに返され、このループは実行が終了するまで継続します。
最も単純な実装は、もちろん非同期ループです。私の実装コードは次のとおりです。



コードをコピーします コードは次のとおりです。 function asyncwhile(fn, interval)
{
if( fn == null || (typeof(fn) != "string" && typeof(fn) != "関数") )
return;
var ラッパー = function()
{
if( (typeof(fn) == "関数" ? fn() : eval(fn) ) != = false )
setTimeout(wrapper, 間隔 == null? 1: 間隔)
}
wrapper();
核心的な内容は次のとおりです: fn 関数の戻り値が false でない場合は、次の setTimeout 登録呼び出しを続行します。

実際、「待機して実行」ロジックは基本的に非同期ループの問題です。この状況を実装する方法の例は次のとおりです。
コードをコピー コードは次のとおりです:

asyncwhile(function (){
if( xxxCondition == false )
return true; // ループが継続することを示します
else
doSomeThing();
return false; / / ループを続行する必要がないことを示します
});

非待機ロジックと実行ロジックの場合、単純な setTimeout で十分です。
非同期は簡単ですが、非同期で注文を実装するのが難しいです。最初の理由は3ステップを実装したかったのですが、2番目の部分は100回を超える非同期ループでした。つまり、実装したい 3 ステップの操作は、実際には 103 個の連続した非同期操作です。ブラウザーで応答待機を実装する方法を見つけるために、頭の中で調べた結果、Firefox での実装しか見つかりませんでした。また、特権呼び出しを申請する必要がありました。
最後に、私は「実行チェーン」の概念を導入する簡単な方法を思いつきました。それは、同じ実行チェーンのすべての登録関数は逐次的であり、異なる実行チェーン間には関係がありません。また、相互排除(ミューテックス)などの概念はありません。同期したい場合はコード内で確認してください。
同じ実行チェーン内で実行トークンが保存され、トークンが関数のシリアル番号と一致した場合にのみ実行が許可され、非同期実行の順序が保証されます。
コードをコピーします コードは次のとおりです。

function asyncSeq(funcArray, chainName, abortWhenError)
{
if( typeof(funcArray) == "function" )
return asyncSeq([funcArray],chainName, abortWhenError);

if( funcArray == null || funcArray. length == 0 )
return;
if(chainName == null )chainName = "__default_seq_chain__"; var tInfo = tInfos[チェーン名] = tInfos[チェーン名] || {カウント : 0, currentIndex : -1, アボート : false};

for(var i = 0; i {
asyncwhile(function(item, tIndex){
return function(){
if( tInfo.abort )
return false;
if( tInfo.currentIndex < tIndex )
return true;
else if( tInfo.currentIndex == tIndex )
{
try{
item()
catch(e); 🎜>if ( abortWhenError ) tInfo.abort = true;
}
finally{
tInfo.currentIndex ;
}
else
{
if( abortWhenError ) tInfo.abort = true;
return false;
}

setTimeout( function() {
if( tInfo.count > 0 && tInfo.currentIndex == -1 )
tInfo.currentIndex = 0;
},20);が追加されました
}


これで、コピー&ペーストに対応した非同期js関数ライブラリが完成しました。具体的な使用例は次のとおりです。




コードをコピー

コードは次のとおりです。

function testAsync()
{
asyncSeq([function(){println("aSyncSeq -0 ");}
, function(){println("aSyncSeq -1 ") ;}
、function(){println("aSyncSeq -2 ");}
、function(){println("aSyncSeq -3 ");}
、function(){println("aSyncSeq -4 ");}
、function(){println("aSyncSeq -5 ");}
、function(){println("aSyncSeq -6 ");}
、function(){ println("aSyncSeq -7 ");}
、function(){println("aSyncSeq -8 ");}
、function(){println("aSyncSeq -9 ");}
、 function(){println("aSyncSeq -10 ");}
, function(){println("aSyncSeq -11 ");}
, function(){println("aSyncSeq -12 ");}
、function(){println("aSyncSeq -13 ");}
、function(){println("aSyncSeq -14 ");}
、function(){println("aSyncSeq -15 ");}
, function(){println("aSyncSeq -16 ");}
, function(){println("aSyncSeq -17 ");}
, function(){println( "aSyncSeq -18 ");}
, function(){println("aSyncSeq -19 ");}
, function(){println("aSyncSeq -20 ");}
, function( ){println("aSyncSeq -21 ");}
、function(){println("aSyncSeq -22 ");}
、function(){println("aSyncSeq -23 ");}
, function(){println("aSyncSeq -24 ");}
, function(){println("aSyncSeq -25 ");}
, function(){println("aSyncSeq -26 ") ;}
、function(){println("aSyncSeq -27 ");}
、function(){println("aSyncSeq -28 ");}
、function(){println("aSyncSeq -29 ");}
]);

asyncSeq([function(){println("aSyncSeq テストチェーン -a0 ");}
, function(){println("aSyncSeq テストチェーン -a1 ");}
、function(){println("aSyncSeq テストチェーン -a2 ");}
、function(){println("aSyncSeq テストチェーン -a3 ");}
、function(){println(" aSyncSeq テストチェーン -a4 ");}
, function(){println("aSyncSeq テストチェーン -a5 ");}
, function(){println("aSyncSeq テストチェーン -a6 ") ;}
, function(){println("aSyncSeq テストチェーン -a7 ");}
, function(){println("aSyncSeq テストチェーン -a8 ");}
], "テストチェーン");

asyncSeq([function(){println("aSyncSeq -a0 ");}
, function(){println("aSyncSeq -a1 ");}
, function(){println ("aSyncSeq -a2 ");}
, function(){println("aSyncSeq -a3 ");}
, function(){println("aSyncSeq -a4 ");}
, 関数(){println("aSyncSeq -a5 ");}
, function(){println("aSyncSeq -a6 ");}
, function(){println("aSyncSeq -a7 ");}
, function(){println("aSyncSeq -a8 ");}
]);
}

var textArea = null;

function println(text)
{
if( textArea == null )
{
textArea = document.getElementById("text");
textArea.value = "";
}

textArea.value = textArea.value text "rn";
}

最後に、要向大家说一声抱歉、很多只想拿代码的朋友恐怕要失望,如果你真的不知道怎么处処これら多余的行号,你可学界の次の表形式の代替案であり、UltraEdit を使用します。
関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!