すべての AJAX 呼び出しを連続的にするにはどうすればよいですか?
-
18-09-2019 - |
質問
jQueryを使っています。また、アプリケーションで並列 AJAX 呼び出しを実行したくありません。各呼び出しは開始する前に前の呼び出しを待機する必要があります。どのように実装すればよいでしょうか?助っ人はいますか?
アップデート XMLHttpRequest または jQuery.post の同期バージョンがある場合は、知りたいです。しかし、シーケンシャル != 同期なので、非同期でシーケンシャルなソリューションが必要です。
解決
これを行うには、同期 ajax 呼び出しを使用するよりもはるかに優れた方法があります。Jquery ajax は deferred を返すため、パイプチェーンを使用するだけで、各 ajax 呼び出しが次の実行前に確実に終了するようにすることができます。これは、より詳細な例を含む実際の例です。 jsfiddle で遊んでみる.
// How to force async functions to execute sequentially
// by using deferred pipe chaining.
// The master deferred.
var dfd = $.Deferred(), // Master deferred
dfdNext = dfd; // Next deferred in the chain
x = 0, // Loop index
values = [],
// Simulates $.ajax, but with predictable behaviour.
// You only need to understand that higher 'value' param
// will finish earlier.
simulateAjax = function (value) {
var dfdAjax = $.Deferred();
setTimeout(
function () {
dfdAjax.resolve(value);
},
1000 - (value * 100)
);
return dfdAjax.promise();
},
// This would be a user function that makes an ajax request.
// In normal code you'd be using $.ajax instead of simulateAjax.
requestAjax = function (value) {
return simulateAjax(value);
};
// Start the pipe chain. You should be able to do
// this anywhere in the program, even
// at the end,and it should still give the same results.
dfd.resolve();
// Deferred pipe chaining.
// What you want to note here is that an new
// ajax call will not start until the previous
// ajax call is completely finished.
for (x = 1; x <= 4; x++) {
values.push(x);
dfdNext = dfdNext.pipe(function () {
var value = values.shift();
return requestAjax(value).
done(function(response) {
// Process the response here.
});
});
}
コードが何をするのか全く分からないとコメントする人もいます。それを理解するには、まず JavaScript の Promise を理解する必要があります。Promise は間もなくネイティブ JavaScript 言語の機能になると私は確信しています。そのため、学習する良い動機になるはずです。
他のヒント
私が考えることができる選択肢は 2 つあります。1 つは、コールバックを介してそれらをチェーンすることです。もう 1 つは、呼び出しを非同期ではなく同期にすることです。
それらを連続的にしたい理由はありますか?が鈍くなるにもほどがあります。
呼び出しを同期にするには、Ajax 呼び出しの async オプションを false に設定します。次のドキュメントを参照してください。 http://docs.jquery.com/Ajax/jQuery.ajax#options (オプションタブをクリックして表示します)。
物語的な JavaScript を試してみてはいかがでしょうか http://www.neilmix.com/narrativejs/doc/
自分では使ったことないけど。これを実行したい場合は、非同期アクションを連鎖させるための何らかの抽象化をセットアップします。他の人が言ったように、ajax オブジェクトの同期バージョンは、応答を待っている間にイベントの処理をブロックします。これにより、ブラウザは応答を受信するまでフリーズしたように見えます。
これを行う最善の方法は、Nosredna が言ったようにコールバックを連鎖させることです。同期 XMLHttpRequest はアプリケーション全体をロックするため、使用はお勧めしません。
私の知る限り、このためのヘルパーはあまりありませんが、コールバック FIFO に似たものを実行できます。
これを見てください: http://docs.jquery.com/Ajax/jQuery.ajax (「オプション」タブをクリックします)。
ただし、同期呼び出しでは応答を受信するまでページがフリーズするため、本番サイトでは使用できないことに注意してください。何らかの理由でブラウザがフリーズした状態で 30 秒待たなければならない場合、ユーザーは怒るからです。
編集:OK、アップデートにより、達成したいことがより明確になりました ;)
したがって、コードは次のようになります。
$.getJSON("http://example.com/jsoncall", function(data) {
process(data);
$.getJSON("http://example.com/jsoncall2", function (data) {
processAgain(data);
$.getJSON("http://example.com/anotherjsoncall", function(data) {
processAgainAndAgain(data);
});
});
});
このようにすると、2 番目の呼び出しは最初の呼び出しへの応答が受信されて処理されたときにのみ発行され、3 番目の呼び出しは 2 番目の呼び出しへの応答が受信されて処理されたときにのみ発行されます。このコードは getJSON 用ですが、$.ajax にも適用できます。
をセットする 非同期 オプションを false に設定します。例:
$.ajax({ async: false /*, your_other_ajax_options_here */ });
参照: Ajax/jQuery.ajax
同期呼び出しは必ずしも遅いわけではありません。AJAX 呼び出しを開いてソケットにポストし、その後ソケットを閉じるアプリがある場合、一部のソケットは 1 つの接続しか処理できないため、ソケットへの複数の呼び出しは意味がありません。その場合、データをキューに入れて、前の AJAX 呼び出しが完了したときにのみ送信されるようにすると、データ スループットが大幅に向上します。
(async () => {
for(f of ['1.json','2.json','3.json']){
var json = await $.getJSON(f);
console.log(json)
};
})()
- jQuery ajax呼び出しを使用して3つのjsonファイルをリクエストします
- await を使用して (並列ではなく) 順番に処理します
- Chrome/Firefox/Edge で動作します (2018/1/30 時点)
もっとで MDN
Promise を使用すると、ajax 呼び出しを連続的に行うことができます。Array のプッシュおよびポップの Promise メソッドを使用すると、連続した Ajax 呼び出しがはるかに簡単になります。
var promises = [Promise.resolve()];
function methodThatReturnsAPromise(id) {
return new Promise((resolve, reject) => {
$.ajax({
url: 'https://jsonplaceholder.typicode.com/todos/'+id,
dataType:'json',
success: function(data)
{
console.log("Ajax Request Id"+id);
console.log(data);
resolve();
}
});
});
}
function pushPromise(id)
{
promises.push(promises.pop().then(function(){
return methodThatReturnsAPromise(id)}));
}
pushPromise(1);
pushPromise(3);
pushPromise(2);
Node.jsイベントを使ってみてはいかがでしょうか?
var EventEmitter = require('events').EventEmitter;
var eventEmitter = new EventEmitter();
var $ = require('jquery');
var doSomething = function (responseData) {
var nextRequestData = {};
// do something with responseData
return nextRequestData;
};
// ajax requests
var request1 = $.ajax;
var request2 = $.ajax;
var requests = [request1, request2];
eventEmitter.on('next', function (i, requestData) {
requests[i](requestData).then(
function (responseData) {
console.log(i, 'request completed');
if (i+1 < requests.length) {
var nextRequestData = doSomething(responseData);
eventEmitter.emit('next', i+1, nextRequestData);
}
else {
console.log('completed all requests');
}
},
function () {
console.log(i, 'request failed');
}
);
});
var data = {
//data to send with request 1
};
eventEmitter.emit('next', 0, data);
シーケンシャル != 同期、非同期およびシーケンシャルのソリューションが必要です
同期実行は一般に「同じクロックを使用する」ことを意味し、順次実行は「順序またはシーケンスに従う」ことを意味します。
特定のユースケースでは、非同期実行は非順次的な結果の可能性を意味するため、両方の条件が満たされる必要があると思います。