ほとんどの人がXMLHttpRequestを使用して非同期リクエストを実行しているようですが、同期リクエストを実行する機能があるという事実は、そうする正当な理由がある可能性があることを示しています。では、その正当な理由は何でしょうか?
ほとんどの人がXMLHttpRequestを使用して非同期リクエストを実行しているようですが、同期リクエストを実行する機能があるという事実は、そうする正当な理由がある可能性があることを示しています。では、その正当な理由は何でしょうか?
回答:
HTML 5標準が進歩するにつれて、それらはより人気になるかもしれないと思います。WebアプリケーションにWebワーカーへのアクセスが許可されている場合、Jonathanが言ったように、開発者が専用のWebワーカーを使用して同期要求を行い、ある要求が別の要求よりも先に発生するようにすることができます。1つのスレッドの現在の状況では、要求が完了するまでブロックするため、理想的な設計とは言えません。
同期XHRは、ユーザーデータの保存に役立ちます。beforeunload
イベントを処理する場合、ユーザーがページを閉じたときにサーバーにデータをアップロードできます。
これがasyncオプションを使用して行われた場合、リクエストが完了する前にページが閉じる可能性があります。これを同期的に実行すると、要求が期待どおりに完了するか失敗することが保証されます。
以下は、非同期リクエストの処理が改善されたため、リクエストが完了するまでユーザーが何かを行うのを意図的にブロックしない限り、同期リクエストを使用する理由が実際にはないことを示唆していますが、配信に失敗しました-悪意があるように聞こえます: )
これは悪いように聞こえるかもしれませんが、ユーザーがページを離れる前、またはアクションが実行される前にリクエスト(または一連のリクエスト)が発生することが重要な場合があります-他のコードの実行をブロックする(たとえば、戻るボタンを防ぐ)設計が不十分なシステムのエラー/メンテナンスを減らす可能性があります。そうは言っても、私はそれを野生で見たことがなく、避けるべきだと強調しています。
ライブラリは、promiseのように、コールバックを介してプロセスを連鎖させることにより、同期性を装います。これは、ブラウザがユーザーの応答性を維持できるようにする、ブロックされないイベントを注文したいという開発ニーズの大部分に適しています(優れたUX)。
Mozillaのドキュメントに記載されたあなたは、同期要求を使用する必要がある場合があります。ただし、このような場合にビーコン(IE / Safariでは使用できません)を使用する回避策もリストされています。これは実験的なものですが、標準の許容範囲に達した場合は、同期要求の棺に釘を打つ可能性があります。
あらゆる種類のトランザクションのような処理で、または任意の操作順序が必要な場所で同期呼び出しを実行する必要があります。
たとえば、曲を再生した後にログアウトするようにイベントをカスタマイズするとします。ログアウト操作が最初に発生した場合、曲は再生されません。これには、リクエストを同期する必要があります。
もう1つの理由は、WebServiceを使用する場合、特にサーバーで計算を実行する場合です。
例:サーバーに値1の変数があります。
Step (1) Perform Update: add 1 to variable Step (2) Perform Update: set variable to the power of 3 End Value: variable equals 8
ステップ(2)が最初に発生した場合、終了値は8ではなく2です。したがって、操作の順序が重要であり、同期が必要です。
一般的な実世界の例では、同期呼び出しが正当化されることはほとんどありません。おそらく、ログインをクリックしてから、ユーザーのログインが必要なサイトの一部をクリックしたときです。
他の人が言っているように、それはあなたのブラウザを拘束するでしょう、それであなたがそうすることができるところでそれから離れてください。
ただし、同期呼び出しの代わりに、ユーザーは現在ロード中のイベントを停止してから、他の操作を実行したい場合がよくあります。ある意味、これは同期です。最初のイベントは2番目のイベントが始まる前に終了するからです。これを行うには、xml接続オブジェクトでabort()メソッドを使用します。
リクエストが受け入れ可能である間にユーザーのブラウザをブロックすることを検討している場合は、必ず同期リクエストを使用してください。
リクエストのシリアル化が目的の場合、これは、前のリクエストのonCompleteコールバックで次の行を起動することにより、非同期リクエストを使用して実現できます。
UIをブロックすることがまさに望ましい動作である実際のケースはたくさんあります。
複数のフィールドを持つアプリを取り上げます。一部のフィールドは、このフィールドの値と他のフィールドの値を入力として提供するリモートサーバーへのxmlhttp呼び出しによって検証する必要があります。
同期モードでは、ロジックは単純で、ユーザーが経験するブロッキングは非常に短く、問題はありません。
非同期モードでは、ユーザーは最初のフィールドの検証中に他のフィールドの値を変更できます。これらの変更により、まだ検証されていない初期フィールドの値を使用して他のxmlhttp呼び出しがトリガーされます。最初の検証が失敗した場合はどうなりますか?純粋な混乱。同期モードが非推奨になり禁止されると、アプリケーションロジックは処理するのが悪夢になります。基本的に、アプリケーションはロックを管理するために書き直す必要があります(たとえば、検証プロセス中に他のアイテムを無効にする)。コードの複雑さは大幅に増加します。そうしないと、ロジック障害が発生し、最終的にデータが破損する可能性があります。
基本的に問題は、ブロックされていないUIエクスペリエンス、またはデータ破損のリスクがより重要なことです。答えは、W3Cではなく、アプリケーション開発者に残しておく必要があります。
完全に機能するために最初のリソースに依存するページ内の他の静的リソースの前に、可変の場所にあるリソースをロードする必要がある場合に使用される同期XHRリクエストの使用法を見ることができます。実際、私はこのようなXHRリクエストを自分の小さなサブプロジェクトに実装していますが、JavaScriptリソースは、特定のパラメーターのセットに応じてサーバー上のさまざまな場所に存在します。後続のJavaScriptリソースはこれらの変数リソースに依存しており、そのようなファイルは、他の依存ファイルがロードされる前にロードされることが保証されている必要があります。これにより、アプリケーション全体が作成されます。
そのアイデアの基盤は、vol7ronの答えを実際に拡張したものです。トランザクションベースの手順は、実際には同期要求を行う必要がある唯一の時間です。他のほとんどの場合、非同期呼び出しは、呼び出し後にDOMが必要に応じて更新されるより良い代替手段です。ユーザーベースのシステムなど、多くの場合、特定の機能は、それ自体がログインするまで「許可されていないユーザー」にロックされる可能性があります。これらの機能は、非同期呼び出しの後、DOM更新手順によってロック解除されます。
最後に、この問題に関するほとんどの個人の意見に同意する必要があります。可能な限り、同期XHRリクエストは回避する必要があります。これは、ブラウザが同期呼び出しでロックされるためです。同期リクエストを実装する場合は、ページの読み込みが実際に行われる前に、たとえばHEADセクションで、ブラウザが通常ロックされる方法で実行する必要があります。
2015年の時点で、デスクトップJavaScriptアプリの人気が高まっています。通常、これらのアプリでは、ローカルファイルをロードするとき(およびXHRを使用してそれらをロードすることは完全に有効なオプションです)、ロード速度が非常に速いため、非同期でコードを過度に複雑にすることはほとんどありません。もちろん、非同期が進むべき方法である場合もあります(インターネットからコンテンツを要求する、非常に大きなファイルまたは膨大な数のファイルを1つのバッチでロードする)が、それ以外の場合は同期は問題なく機能します(そしてはるかに使いやすくなります) 。
理由:
ユーザーが対話を行う前に、サーバーからさまざまなデータをロードするために半ダースのhttp取得を実行する必要があるajaxアプリケーションがあるとします。
明らかに、これをオンロードからトリガーする必要があります。
同期呼び出しは、コードを複雑にすることなく、これに非常に適しています。シンプルでわかりやすいです。
欠点:
唯一の欠点は、すべてのデータが読み込まれるか、タイムアウトが発生するまでブラウザがロックされることです。問題のajaxアプリケーションに関しては、とにかくすべての初期データがロードされるまでアプリケーションは役に立たないので、これはそれほど問題ではありません。
代替案?
ただし、多くのブラウザは、JavaScriptがいずれかのウィンドウでビジー状態のときにすべてのウィンドウ/タブをロックします。これは、ブラウザの設計上の愚かな問題です。ただし、結果として、ユーザーが他のタブを使用できないようにする場合、低速のネットワーク取得をブロックすることは適切ではありません。 ajaxページがロードされるのを待っている間。
ただし、とにかく最近のブラウザから同期取得が削除または制限されているようです。それは、誰かがいつも悪いと判断したためなのか、それともブラウザの作成者がこのトピックに関するWCワーキングドラフトに混乱したためなのかはわかりません。
http://www.w3.org/TR/2012/WD-XMLHttpRequest-20120117/#the-open-methodは、ブロッキングモードを使用するときにタイムアウトを設定できないように見えます(セクション4.7.3を参照)。 。私には直感に反しているようです。IOをブロックするときはいつでも、適切なタイムアウトを設定するのが礼儀です。それでは、なぜユーザーが指定したタイムアウトではなく、IOのブロックを許可するのでしょうか。
私の意見では、IOのブロックは状況によっては重要な役割を果たしますが、正しく実装する必要があります。1つのブラウザタブまたはウィンドウが他のすべてのタブまたはウィンドウをロックすることは許容されませんが、それはブラウザの設計上の欠陥です。恥が原因である恥。ただし、場合によっては、個々のタブまたはウィンドウが数秒間応答しなくなること(つまり、ブロッキングIO / HTTP GETを使用すること)が完全に許容される場合があります。たとえば、ページの読み込み時、おそらく大量のデータとにかく何かをする前にある必要があります。適切に実装されたブロッキングコードが最もクリーンな方法である場合があります。
もちろん、この場合の同等の関数は非同期http getを使用して取得できますが、どのような間抜けなルーチンが必要ですか?
私はこれらの線に沿って何かを試みると思います:
ドキュメントのロード時に、次の手順を実行します。1:0に初期化された6つのグローバル「完了」フラグ変数を設定します。2:6つのバックグラウンド取得をすべて実行します(順序は重要ではないと想定)。
次に、6つのhttp getのそれぞれの完了コールバックは、それぞれの「完了」フラグを設定します。また、各コールバックは、他のすべての完了フラグをチェックして、6つのHTTP取得がすべて完了したかどうかを確認します。完了する最後のコールバックは、他のすべてが完了したことを確認すると、REAL init関数を呼び出し、データがすべてフェッチされたので、すべてをセットアップします。
フェッチの順序が重要な場合、またはWebサーバーが複数のリクエストを同時に受け入れることができなかった場合は、次のようなものが必要になります。
onload()では、最初のhttpgetが起動されます。そのコールバックでは、2番目のものが起動されます。コールバックでは、3番目の-などが続き、各コールバックは次のHTTPGETを起動します。最後のものが戻ったとき、それは本当のinit()ルーチンを呼び出すでしょう。
本番コードで同期呼び出しを行うとどうなりますか?
空が落ちる。
真剣に、ユーザーはロックされたブラウザが好きではありません。
ユーザー名がまだ存在しないことを確認する際に、ユーザー名を検証するために使用します。
これは非同期で行う方がよいと思いますが、この特定の検証ルールには別のコードを使用する必要があります。私はよりよく説明します。私の検証設定では、データが有効かどうかに応じてtrueまたはfalseを返すいくつかの検証関数を使用しています。
関数が戻らなければならないので、非同期の手法を使用することはできません。それを同期化するだけで、サーバーが目立たないように十分迅速に応答することを期待しています。AJAXコールバックを使用した場合、残りの実行を他の検証メソッドとは異なる方法で処理する必要があります。
false
)をチェックさせ、サーバーが応答したときにフラグをtrueまたはfalseに設定することです。フィールドを変更すると、フラグがリセットされ、サーバーが再度呼び出されます。
SYNCとASYNC:違いは何ですか?
基本的にそれはこれに要約されます:
console.info('Hello, World!');
doSomething(function handleResult(result) {
console.info('Got result!');
});
console.info('Goodbye cruel world!');
ときdoSomething
である同期これは印刷になります。
Hello, World!
Got result!
Goodbye cruel world!
対照的に、doSomething
が非同期の場合、これは次のように出力されます。
Hello, World!
Goodbye cruel world!
Got result!
関数doSomething
は非同期で作業を行っているため、作業が完了する前に戻ります。したがって、印刷後にのみ結果が得られますGoodbye cruel world!
非同期呼び出しの結果に依存している場合は、依存するコードをコールバックに配置する必要があります。
console.info('Hello, World!');
doSomething(function handleResult(result) {
console.info('Got result!');
if (result === 'good') {
console.info('I feel great!');
}
else {
console.info('Goodbye cruel world!');
}
});
そのため、2つまたは3つのことが順番に発生する必要があるという事実だけで、それらを同期的に実行する理由はありません(ただし、同期コードはほとんどの人にとって扱いやすいです)。
同期XMLHTTPREQUESTを使用する理由
呼び出された関数が完了する前に結果が必要になる場合があります。このシナリオを検討してください。
function lives(name) {
return (name !== 'Elvis');
}
console.info('Elvis ' + (lives('Elvis') ? 'lives!' : 'has left the building...');
呼び出し元のコード(console.info
行)を制御lives
できず、サーバーに問い合わせるために関数を変更する必要があるとします...サーバーに対して内部から非同期要求を実行し、完了するlives
前に応答を得る方法はありませんlives
。だから我々は返すかどうか分からないでしょうtrue
かfalse
。関数が完了する前に結果を取得する唯一の方法は、同期要求を実行することです。
Sami Samhuri
彼の答えに言及、あなたはあなたの関数が終了する前に、サーバーの要求に対する答えを必要とするかもしれない非常に現実的なシナリオがあるonbeforeunload
、それは、ウィンドウが閉じられる前に、これまでに実行されますあなたのアプリからの最後の関数だとして、イベント。
同期呼び出しは必要ありませんが、簡単なのでとにかく使用します
しないでください。同期呼び出しはブラウザをロックし、アプリが応答しなくなったように感じさせます。しかし、あなたは正しいです。非同期コードは難しいです。ただし、対処をはるかに簡単にする方法があります。同期コードほど簡単ではありませんが、近づいています:Promises。
次に例を示します。コードの3番目のセグメントが実行される前に、2つの非同期呼び出しが両方とも正常に完了する必要があります。
var carRented = rentCar().then(function(car){
gasStation.refuel(car);
});
var hotelBooked = bookHotel().then(function(reservation) {
reservation.confirm();
});
Promise.all([carRented, hotelBooked]).then(function(){
// At this point our car is rented and our hotel booked.
goOnHoliday();
});
実装方法は次のbookHotel
とおりです。
function bookHotel() {
return new Promise(function(resolve, reject){
if (roomsAvailable()) {
var reservation = reserveRoom();
resolve(reservation);
}
else {
reject(new Error('Could not book a reservation. No rooms available.'));
}
});
}
XMLHttpRequest
従来、非同期リクエストに使用されていました。時々(デバッグまたは特定のビジネスロジックのために)、同期するために1ページの非同期呼び出しのすべて/いくつかを変更したい場合があります。
JSコードのすべてを変更せずにそれを実行したいと思います。async / syncフラグはその機能を提供し、正しく設計されていれば、コードの1行を変更するかvar
、実行時に1の値を変更するだけで済みます。
Firefox(およびおそらくすべての非IEブラウザー)は非同期XHRタイムアウトをサポートしていません。
HTML5 WebWorkersサポートのタイムアウトを行います。したがって、同期XHRリクエストをタイムアウト付きでWebWorkerにラップして、タイムアウト動作付きの非同期のようなXHRを実装することをお勧めします。
同期HTTPリクエストの使用は、モバイル広告ビジネスでは一般的な方法です。
アプリケーションを構築する企業(別名「パブリッシャー」)は、収益を上げるために広告を掲載することがよくあります。このために、彼らは広告SDKをアプリにインストールします。多くが存在します(MoPub、Ogury、TapJob、AppNext、Google Ads AdMob)。
これらのSDKは、Webビューで広告を配信します。
ユーザーに広告を配信するとき、特にビデオを再生するときは、スムーズなエクスペリエンスである必要があります。いかなる時点でもバッファリングやロードは行わないでください。
これを解決するためにprecaching
使用されます。メディア(画像/ビデオなど)がWebビューのバックグラウンドで同期的にロードされる場所。
非同期でやってみませんか?
onload
イベントをリッスンして、広告をユーザーに配信する準備ができたことを確認します。同期XMLHttpRequestsの廃止に伴い、別の方法を決定できない限り、広告ビジネスは将来的に標準を変更せざるを得なくなる可能性があります。
同期XHRは、(非本番の)内部ツールやフレームワークの開発に非常に役立ちます。たとえば、次のように、最初のアクセス時にコードライブラリを同期的にロードしたいとします。
get draw()
{
if (!_draw)
{
let file;
switch(config.option)
{
case 'svg':
file = 'svgdraw.js';
break;
case 'canvas':
file = 'canvasdraw.js';
break;
default:
file = 'webgldraw.js';
}
var request = new XMLHttpRequest();
request.open('GET', file, false);
request.send(null);
_draw = eval(request.responseText);
}
return _draw;
}
気が狂って、盲目的に評価の悪を逆流させる前に、これはローカルテスト専用であることを覚えておいてください。本番ビルドの場合、_drawはすでに設定されています。
したがって、コードは次のようになります。
foo.drawLib.draw.something(); //loaded on demand
これは、同期XHRなしでは実行できないことのほんの一例です。このライブラリを事前にロードすることも、promise / callbackを実行することもできますが、同期XHRなしでライブラリを同期的にロードすることはできません。このタイプのものがあなたのコードをどれだけクリーンアップできるか考えてください...
ツールとフレームワーク(ローカルで実行)に対してこれを使用して実行できることの制限は、想像力によってのみ制限されます。ただし、JavaScriptの世界では想像力が少し制限されているようです。
さてここに1つの正当な理由があります。httpリクエストを実行したかったので、結果に応じて、入力type = fileでclick()を呼び出します。これは、非同期xhrまたはフェッチでは不可能です。コールバックはコンテキスト「ユーザーアクション」を失うため、click()の呼び出しは無視されます。同期xhrは私のベーコンを救いました。
onclick(event){
//here I can, but I don't want to.
//document.getElementById("myFileInput").click();
fetch("Validate.aspx", { method : "POST", body: formData, credentials: "include" })
.then((response)=>response.json())
.then(function (validResult) {
if (validResult.success) {
//here, I can't.
document.getElementById("myFileInput").click();
}
});
}