Tüm jQuery Ajax istekleri başka bir işlev içinde yapılana kadar bir işlevi nasıl bekleyebilirim?
Kısacası, bir sonraki yürütmeden önce tüm Ajax isteklerinin yapılmasını beklemem gerekiyor. Ama nasıl?
Tüm jQuery Ajax istekleri başka bir işlev içinde yapılana kadar bir işlevi nasıl bekleyebilirim?
Kısacası, bir sonraki yürütmeden önce tüm Ajax isteklerinin yapılmasını beklemem gerekiyor. Ama nasıl?
Yanıtlar:
jQuery şimdi bu amaçla bir when işlevi tanımlar .
Herhangi bir sayıda Ertelenmiş nesneyi bağımsız değişken olarak kabul eder ve hepsi çözüldüğünde bir işlevi yürütür.
Bu, örneğin dört ajax isteği başlatmak (örneğin), ardından tamamlandığında bir eylem gerçekleştirmek istiyorsanız, şöyle bir şey yapabilirsiniz:
$.when(ajax1(), ajax2(), ajax3(), ajax4()).done(function(a1, a2, a3, a4){
// the code here will be executed when all four ajax requests resolve.
// a1, a2, a3 and a4 are lists of length 3 containing the response text,
// status, and jqXHR object for each of the four ajax calls respectively.
});
function ajax1() {
// NOTE: This function must return the value
// from calling the $.ajax() method.
return $.ajax({
url: "someUrl",
dataType: "json",
data: yourJsonData,
...
});
}
Kanımca, temiz ve açık bir sözdizimi sağlar ve sayfanız geliştikçe istenmeyen yan etkilere sahip olabilecek ajaxStart ve ajaxStop gibi global değişkenleri dahil etmekten kaçınır.
Kaç tane ajax argümanı beklemeniz gerektiğini önceden bilmiyorsanız (yani, değişken sayıda argüman kullanmak istiyorsanız), yine de yapılabilir, ancak biraz daha karmaşıktır. Bkz . Deferreds dizisini $ .when () öğesine (ve belki de değişken sayıda argümanla sorun giderirken jQuery .
Ajax betiklerinin vb. Hata modları üzerinde daha derin kontrole ihtiyacınız varsa, döndürülen nesneyi kaydedebilirsiniz .when()
- bu , tüm orijinal ajax sorgularını kapsayan bir jQuery Promise nesnesidir. Ayrıntılı başarı / başarısızlık işleyicileri eklemek için .then()
veya .fail()
üzerinde arama yapabilirsiniz .
$.when
bir Promise
nesneyi döndürdüğüne dikkat edilmelidir .done
. Örneğin, .then(onSuccess, onFailure)
yöntemle, her iki istek de başarılı olduğunda veya en az biri başarısız olduğunda yanıt verebilirsiniz.
fail
Davaya dikkat edin . Bunun aksine done
, fail
ilk başarısızlık anında ateşler ve kalan ertelemeleri göz ardı eder.
onFailure
fonksiyonun eklenebileceğini vurguladığınız için teşekkürler . OP'nin sorusuna yaptığı bir yorumda belirttiğim gibi: "bitti" ile ne demek istediğini daha kesin olarak belirtmek isteyebilir. "Ryan Mohr" da fail
farklı davranan gerçeği ile ilgili çok iyi bir noktaya sahipti, sanırım html5rocks.com/en/tutorials/es6/promisesdone
hakkında yapılması gereken bazı okumalarPromises
Kaç tane istek olursa olsun, belgenizdeki tüm ajax
isteklerin ne zaman tamamlandığını bilmek istiyorsanız , $ .ajaxStop olayını şu şekilde kullanın:
$(document).ajaxStop(function () {
// 0 === $.active
});
Bu durumda, uygulamada ne kadar istek gerçekleştiğini, gelecekte bitirilebileceğini tahmin etmeniz veya karmaşık mantık işlevlerine girmeniz veya hangi işlevlerin
HTTP(S)
istek yaptığını bulmanız gerekmez .
$.ajaxStop
buradaHTML
requst tarafından değiştirilebileceğini düşündüğünüz herhangi bir düğüme de bağlanabilir .
Güncelleme:
Eğer sopa ile isterseniz ES
sözdizimi, o zaman kullanabilirsiniz Promise.all bilinen için ajax
yöntemlere:
Promise.all([ajax1(), ajax2()]).then(() => {
// all requests finished successfully
}).catch(() => {
// all requests finished but one or more failed
})
Burada ilginç olan nokta, her iki çalışmasıdır Promises
ve $.ajax
istekleri.
İşte jsFiddle gösterisi.
Güncelleme 2: Async / await sözdizimini
kullanan daha yeni bir sürüm :
try {
const results = await Promise.all([ajax1(), ajax2()])
// do other actions
} catch(ex) { }
Ben buldum iyi bir cevap ile gnarf tam olarak aradığım şey olan :)
jQuery ajaxQueue
//This handles the queues
(function($) {
var ajaxQueue = $({});
$.ajaxQueue = function(ajaxOpts) {
var oldComplete = ajaxOpts.complete;
ajaxQueue.queue(function(next) {
ajaxOpts.complete = function() {
if (oldComplete) oldComplete.apply(this, arguments);
next();
};
$.ajax(ajaxOpts);
});
};
})(jQuery);
Ardından kuyruğa şu şekilde bir ajax isteği ekleyebilirsiniz:
$.ajaxQueue({
url: 'page.php',
data: {id: 1},
type: 'POST',
success: function(data) {
$('#status').html(data);
}
});
ajaxStop
Etkinliği kullanın .
Örneğin, 100 ajax isteği getirilirken bir yükleme ... mesajınız olduğunu ve yüklendikten sonra bu mesajı gizlemek istediğinizi varsayalım.
JQuery belgesinden :
$("#loading").ajaxStop(function() {
$(this).hide();
});
Bu sayfada yapılan tüm ajax isteklerinin bekleyeceğini unutmayın.
NOT: Yukarıdaki yanıtlar, bu yanıtın yazıldığı sırada mevcut olmayan işlevleri kullanır. jQuery.when()
Bu yaklaşımlar yerine kullanılmasını öneriyorum ama cevabı tarihsel amaçlar için bırakıyorum.
-
Muhtemelen basit bir sayma semaforu ile başarabilirsiniz, ancak nasıl uyguladığınız kodunuza bağlı olacaktır. Basit bir örnek ...
var semaphore = 0, // counting semaphore for ajax requests
all_queued = false; // bool indicator to account for instances where the first request might finish before the second even starts
semaphore++;
$.get('ajax/test1.html', function(data) {
semaphore--;
if (all_queued && semaphore === 0) {
// process your custom stuff here
}
});
semaphore++;
$.get('ajax/test2.html', function(data) {
semaphore--;
if (all_queued && semaphore === 0) {
// process your custom stuff here
}
});
semaphore++;
$.get('ajax/test3.html', function(data) {
semaphore--;
if (all_queued && semaphore === 0) {
// process your custom stuff here
}
});
semaphore++;
$.get('ajax/test4.html', function(data) {
semaphore--;
if (all_queued && semaphore === 0) {
// process your custom stuff here
}
});
// now that all ajax requests are queued up, switch the bool to indicate it
all_queued = true;
Bunun {async: false} gibi çalışmasını istiyorsanız, ancak tarayıcıyı kilitlemek istemediyseniz, aynı şeyi bir jQuery kuyruğuyla da başarabilirsiniz.
var $queue = $("<div/>");
$queue.queue(function(){
$.get('ajax/test1.html', function(data) {
$queue.dequeue();
});
}).queue(function(){
$.get('ajax/test2.html', function(data) {
$queue.dequeue();
});
}).queue(function(){
$.get('ajax/test3.html', function(data) {
$queue.dequeue();
});
}).queue(function(){
$.get('ajax/test4.html', function(data) {
$queue.dequeue();
});
});
.get()
. Bu şekilde en azından bu kodu çoğaltmazsınız. Sadece bu değil, function(){}
her seferinde bildirmek her seferinde bellek ayırır! Statik olarak tanımlanmış bir işlev çağırabiliyorsanız oldukça kötü uygulama.
javascript olay tabanlıdır, bu nedenle asla beklememelisiniz , kanca / geri arama ayarlamalısınız
Muhtemelen jquery.ajax'ın başarı / tam yöntemlerini kullanabilirsiniz.
Veya .ajaxComplete kullanabilirsiniz :
$('.log').ajaxComplete(function(e, xhr, settings) {
if (settings.url == 'ajax/test.html') {
$(this).text('Triggered ajaxComplete handler.');
//and you can do whatever other processing here, including calling another function...
}
});
gerçi ajax istek (ler) inizin nasıl daha kesin olarak adlandırıldığına dair bir takma kod göndermelisiniz ...
Küçük bir çözüm şöyle:
// Define how many Ajax calls must be done
var ajaxCalls = 3;
var counter = 0;
var ajaxCallComplete = function() {
counter++;
if( counter >= ajaxCalls ) {
// When all ajax calls has been done
// Do something like hide waiting images, or any else function call
$('*').css('cursor', 'auto');
}
};
var loadPersons = function() {
// Show waiting image, or something else
$('*').css('cursor', 'wait');
var url = global.ctx + '/loadPersons';
$.getJSON(url, function(data) {
// Fun things
})
.complete(function() { **ajaxCallComplete();** });
};
var loadCountries = function() {
// Do things
var url = global.ctx + '/loadCountries';
$.getJSON(url, function(data) {
// Travels
})
.complete(function() { **ajaxCallComplete();** });
};
var loadCities = function() {
// Do things
var url = global.ctx + '/loadCities';
$.getJSON(url, function(data) {
// Travels
})
.complete(function() { **ajaxCallComplete();** });
};
$(document).ready(function(){
loadPersons();
loadCountries();
loadCities();
});
Umut faydalı olabilir ...
jQuery, ajax isteğinin eşzamansız olmasını isteyip istemediğinizi belirtmenize olanak tanır. Yalnızca ajax isteklerini senkronize edebilirsiniz ve kodun geri kalanı geri dönünceye kadar yürütülmez.
Örneğin:
jQuery.ajax({
async: false,
//code
});
Basit bir şeye ihtiyacınız varsa; bir kez ve geri arama bitti
//multiple ajax calls above
var callback = function () {
if ($.active !== 0) {
setTimeout(callback, '500');
return;
}
//whatever you need to do here
//...
};
callback();
Ayrıca async.js kullanabilirsiniz .
Ben sadece $ .when zaman zaman ajax istekleri değil, zaman aşımları, SqlLite çağrıları vb gibi kutudan vaat desteklemiyor asenkron çağrı her türlü birleştirebilirsiniz çünkü daha iyi olduğunu düşünüyorum.
@BBonifield yanıtı temelinde, semafor mantığının tüm ajax çağrılarına yayılmaması için bir yardımcı program yazdım.
untilAjax
tüm ajaxCall'lar tamamlandığında bir geri çağırma işlevi çağıran yardımcı program işlevidir.
ajaxObjs
ajax ayar nesneleri dizisidir [http://api.jquery.com/jQuery.ajax/]
.
fn
geri arama işlevi
function untilAjax(ajaxObjs, fn) {
if (!ajaxObjs || !fn) {
return;
}
var ajaxCount = ajaxObjs.length,
succ = null;
for (var i = 0; i < ajaxObjs.length; i++) { //append logic to invoke callback function once all the ajax calls are completed, in success handler.
succ = ajaxObjs[i]['success'];
ajaxObjs[i]['success'] = function(data) { //modified success handler
if (succ) {
succ(data);
}
ajaxCount--;
if (ajaxCount == 0) {
fn(); //modify statement suitably if you want 'this' keyword to refer to another object
}
};
$.ajax(ajaxObjs[i]); //make ajax call
succ = null;
};
Örnek: doSomething
işlev kullanır untilAjax
.
function doSomething() {
// variable declarations
untilAjax([{
url: 'url2',
dataType: 'json',
success: function(data) {
//do something with success data
}
}, {
url: 'url1',
dataType: 'json',
success: function(data) {
//do something with success data
}
}, {
url: 'url2',
dataType: 'json',
success: function(response) {
//do something with success data
}
}], function() {
// logic after all the calls are completed.
});
}
Sıfırdan başlıyorsanız $ .when () kullanmanızı tavsiye ederim .
Bu sorunun milyondan fazla yanıtı olmasına rağmen, davam için hala yararlı bir şey bulamadım. Diyelim ki, zaten bazı ajax çağrıları yapmak ve vaatlerin karmaşıklığını tanıtmak ve / veya her şeyi yeniden yapmak istemiyorsanız, mevcut bir kod tabanı ile uğraşmak zorundasınız.
Biz kolayca jQuery yararlanabilir .data
, .on
ve .trigger
sonsuza beri jQuery bir parçası olmuştur fonksiyonları.
Çözümümle ilgili iyi şeyler:
Geri aramanın tam olarak neye bağlı olduğu açıktır
işlev triggerNowOrOnLoaded
, verilerin önceden yüklenmiş olup olmadığını umursamıyor veya hala bekliyoruz
mevcut bir koda takmak çok kolay
$(function() {
// wait for posts to be loaded
triggerNowOrOnLoaded("posts", function() {
var $body = $("body");
var posts = $body.data("posts");
$body.append("<div>Posts: " + posts.length + "</div>");
});
// some ajax requests
$.getJSON("https://jsonplaceholder.typicode.com/posts", function(data) {
$("body").data("posts", data).trigger("posts");
});
// doesn't matter if the `triggerNowOrOnLoaded` is called after or before the actual requests
$.getJSON("https://jsonplaceholder.typicode.com/users", function(data) {
$("body").data("users", data).trigger("users");
});
// wait for both types
triggerNowOrOnLoaded(["posts", "users"], function() {
var $body = $("body");
var posts = $body.data("posts");
var users = $body.data("users");
$body.append("<div>Posts: " + posts.length + " and Users: " + users.length + "</div>");
});
// works even if everything has already loaded!
setTimeout(function() {
// triggers immediately since users have been already loaded
triggerNowOrOnLoaded("users", function() {
var $body = $("body");
var users = $body.data("users");
$body.append("<div>Delayed Users: " + users.length + "</div>");
});
}, 2000); // 2 seconds
});
// helper function
function triggerNowOrOnLoaded(types, callback) {
types = $.isArray(types) ? types : [types];
var $body = $("body");
var waitForTypes = [];
$.each(types, function(i, type) {
if (typeof $body.data(type) === 'undefined') {
waitForTypes.push(type);
}
});
var isDataReady = waitForTypes.length === 0;
if (isDataReady) {
callback();
return;
}
// wait for the last type and run this function again for the rest of the types
var waitFor = waitForTypes.pop();
$body.on(waitFor, function() {
// remove event handler - we only want the stuff triggered once
$body.off(waitFor);
triggerNowOrOnLoaded(waitForTypes, callback);
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>Hi!</body>
Tüm ajax yükü tamamlandığında boyut kontrolü kullanıyorum
function get_ajax(link, data, callback) {
$.ajax({
url: link,
type: "GET",
data: data,
dataType: "json",
success: function (data, status, jqXHR) {
callback(jqXHR.status, data)
},
error: function (jqXHR, status, err) {
callback(jqXHR.status, jqXHR);
},
complete: function (jqXHR, status) {
}
})
}
function run_list_ajax(callback){
var size=0;
var max= 10;
for (let index = 0; index < max; index++) {
var link = 'http://api.jquery.com/ajaxStop/';
var data={i:index}
get_ajax(link,data,function(status, data){
console.log(index)
if(size>max-2){
callback('done')
}
size++
})
}
}
run_list_ajax(function(info){
console.log(info)
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
Alex'in cevabını genişletmek için, değişken argümanları ve vaatleri olan bir örneğim var. Ajax aracılığıyla görüntüleri yüklemek ve hepsi yüklendikten sonra bunları sayfada görüntülemek istedim.
Bunu yapmak için aşağıdakileri kullandım:
let urlCreator = window.URL || window.webkitURL;
// Helper function for making ajax requests
let fetch = function(url) {
return $.ajax({
type: "get",
xhrFields: {
responseType: "blob"
},
url: url,
});
};
// Map the array of urls to an array of ajax requests
let urls = ["https://placekitten.com/200/250", "https://placekitten.com/300/250"];
let files = urls.map(url => fetch(url));
// Use the spread operator to wait for all requests
$.when(...files).then(function() {
// If we have multiple urls, then loop through
if(urls.length > 1) {
// Create image urls and tags for each result
Array.from(arguments).forEach(data => {
let imageUrl = urlCreator.createObjectURL(data[0]);
let img = `<img src=${imageUrl}>`;
$("#image_container").append(img);
});
}
else {
// Create image source and tag for result
let imageUrl = urlCreator.createObjectURL(arguments[0]);
let img = `<img src=${imageUrl}>`;
$("#image_container").append(img);
}
});
Tek veya birden fazla URL'de çalışacak şekilde güncellendi: https://jsfiddle.net/euypj5w9/
Belirtilen diğer yanıtlar gibi, ajaxStop()
tüm ajax isteği tamamlanana kadar beklemek için kullanabilirsiniz .
$(document).ajaxStop(function() {
// This function will be triggered every time any ajax request is requested and completed
});
Belirli bir ajax()
istek için yapmak istiyorsanız, yapabileceğiniz en iyi şey complete()
, belirli ajax isteğinin içindeki yöntemi kullanmaktır :
$.ajax({
type: "POST",
url: "someUrl",
success: function(data) {
// This function will be triggered when ajax returns a 200 status code (success)
},
complete: function() {
// This function will be triggered always, when ajax request is completed, even it fails/returns other status code
},
error: function() {
// This will be triggered when ajax request fail.
}
});
Ancak, sadece birkaç ve bazı ajax isteğinin yapılması için beklemek gerekiyorsa? Beklemek istediğiniz bu ajax bitene kadar beklemek için harika javascript vaatlerini kullanın . Size vaatlerin ajax ile nasıl çalıştığını göstermek için kısa, kolay ve okunabilir bir örnek verdim.
Lütfen bir sonraki örneğe göz atın . Kullandığım setTimeout
örnek açıklamak.
// Note:
// resolve() is used to mark the promise as resolved
// reject() is used to mark the promise as rejected
$(document).ready(function() {
$("button").on("click", function() {
var ajax1 = new Promise((resolve, reject) => {
$.ajax({
type: "GET",
url: "https://miro.medium.com/max/1200/0*UEtwA2ask7vQYW06.png",
xhrFields: { responseType: 'blob'},
success: function(data) {
setTimeout(function() {
$('#image1').attr("src", window.URL.createObjectURL(data));
resolve(" Promise ajax1 resolved");
}, 1000);
},
error: function() {
reject(" Promise ajax1 rejected");
},
});
});
var ajax2 = new Promise((resolve, reject) => {
$.ajax({
type: "GET",
url: "https://cdn1.iconfinder.com/data/icons/social-media-vol-1-1/24/_github-512.png",
xhrFields: { responseType: 'blob' },
success: function(data) {
setTimeout(function() {
$('#image2').attr("src", window.URL.createObjectURL(data));
resolve(" Promise ajax2 resolved");
}, 1500);
},
error: function() {
reject(" Promise ajax2 rejected");
},
});
});
var ajax3 = new Promise((resolve, reject) => {
$.ajax({
type: "GET",
url: "https://miro.medium.com/max/632/1*LUfpOf7teWvPdIPTBmYciA.png",
xhrFields: { responseType: 'blob' },
success: function(data) {
setTimeout(function() {
$('#image3').attr("src", window.URL.createObjectURL(data));
resolve(" Promise ajax3 resolved");
}, 2000);
},
error: function() {
reject(" Promise ajax3 rejected");
},
});
});
Promise.all([ajax1, ajax2, ajax3]).then(values => {
console.log("We waited until ajax ended: " + values);
console.log("My few ajax ended, lets do some things!!")
}, reason => {
console.log("Promises failed: " + reason);
});
// Or if you want wait for them individually do it like this
// ajax1.then(values => {
// console.log("Promise 1 resolved: " + values)
// }, reason => {
// console.log("Promise 1 failed: " + reason)
// });
});
});
img {
max-width: 200px;
max-height: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button>Make AJAX request</button>
<div id="newContent">
<img id="image1" src="">
<img id="image2" src="">
<img id="image3" src="">
</div>
Basit bir yol buldum, shift()
function waitReq(id)
{
jQuery.ajax(
{
type: 'POST',
url: ajaxurl,
data:
{
"page": id
},
success: function(resp)
{
...........
// check array length if not "0" continue to use next array value
if(ids.length)
{
waitReq(ids.shift()); // 2
)
},
error: function(resp)
{
....................
if(ids.length)
{
waitReq(ids.shift());
)
}
});
}
var ids = [1, 2, 3, 4, 5];
// shift() = delete first array value (then print)
waitReq(ids.shift()); // print 1
Benim çözümüm aşağıdaki
var request;
...
'services': {
'GetAddressBookData': function() {
//This is the primary service that loads all addressbook records
request = $.ajax({
type: "POST",
url: "Default.aspx/GetAddressBook",
contentType: "application/json;",
dataType: "json"
});
},
...
'apps': {
'AddressBook': {
'data': "",
'Start': function() {
...services.GetAddressBookData();
request.done(function(response) {
trace("ajax successful");
..apps.AddressBook.data = response['d'];
...apps.AddressBook.Filter();
});
request.fail(function(xhr, textStatus, errorThrown) {
trace("ajax failed - " + errorThrown);
});
Oldukça güzel çalıştı. Bunu yapmanın birçok farklı yolunu denedim, ama bunu en basit ve en yeniden kullanılabilir olarak buldum. Umarım yardımcı olur
Çözümüme bak:
Bu işlevi (ve değişkeni) javascript dosyanıza ekleyin:
var runFunctionQueue_callback;
function runFunctionQueue(f, index, callback) {
var next_index = index + 1
if (callback !== undefined) runFunctionQueue_callback = callback;
if (f[next_index] !== undefined) {
console.log(index + ' Next function avalaible -> ' + next_index);
$.ajax({
type: 'GET',
url: f[index].file,
data: (f[index].data),
complete: function() {
runFunctionQueue(f, next_index);
}
});
} else {
console.log(index + ' Last function');
$.ajax({
type: 'GET',
url: f[index].file,
data: (f[index].data),
async: false,
complete: runFunctionQueue_callback
});
}
}
2.İsteğiniz gibi bir dizi oluşturun:
var f = [
{file: 'file_path', data: {action: 'action', data: 'any_data}},
{file: 'file_path', data: {action: 'action', data: 'any_data}},
{file: 'file_path', data: {action: 'action', data: 'any_data}},
{file: 'file_path', data: {action: 'action', data: 'any_data}}
];
3. geri arama fonksiyonu oluşturun:
function Function_callback() {
alert('done');
}
4. runFunctionQueue işlevini parametrelerle arayın:
runFunctionQueue(f, 0, QuestionInsert_callback);
// first parameter: array with requests data
// second parameter: start from first request
// third parameter: the callback function
$.when
burada açıklandığı gibi çalışmak callback(x)
yerine benim için çalışmıyor return x
: https://stackoverflow.com/a/13455253/10357604
Bu şekilde dene. ajax çağrısı bitene kadar beklemek için java script fonksiyonu içinde bir döngü yapın.
function getLabelById(id)
{
var label = '';
var done = false;
$.ajax({
cache: false,
url: "YourMvcActionUrl",
type: "GET",
dataType: "json",
async: false,
error: function (result) {
label='undefined';
done = true;
},
success: function (result) {
label = result.Message;
done = true;
}
});
//A loop to check done if ajax call is done.
while (!done)
{
setTimeout(function(){ },500); // take a sleep.
}
return label;
}
setTimeout()
değil take a sleep
. Bu durumda, done
gerçek olana kadar tüm sekmeleri engellersiniz .
done
while döngüsü devam ederken asla doğru olmayacak. While döngüsü çalışıyorsa, olay döngüsü devam edemez ve bu nedenle ajax başarısı için geri aramayı asla çalıştırmaz.