Ne zaman uyumsuz bir çağrı yanıt verilecek?
Bir işlevi var bir Ajax isteği yapar foo
. Nasıl foo
gelen yanıt iade edebilir miyim?
İşlev içinde success
geri yanı sıra yerel bir değişken için yanıt atama değeri geri dönmek ve geri dönmek için çalıştım, ama bu yollardan hiçbiri aslında yanıt verir.
function foo() {
var result;
$.ajax({
url: '...',
success: function(response) {
result = response;
// return response; // <- tried that one as well
}
});
return result;
}
var result = foo(); // always ends up being `undefined`.
CEVAP
Farklı örnekler ile uyumsuz davranışı daha genel açıklama
->
lütfen bakınWhy is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
->
Eğer zaten sorunu anlamak, Olası çözümler aşağıda atlayın.
Sorun açıklaması
BirAJAX duruyorzaman uyumsuz. Bu isteği (ya da daha doğrusu yanıt alma) gönderme normal yürütme akışını alınır anlamına gelir. , $.ajax
örnek hemen döner ve bir sonraki deyimi, return result;
, success
geri arama bile çağırılmış gibi geçtin işlevi önce yürütülür.
Burada umarım senkron ve asenkron akış arasındaki farkı daha net hale getiren bir benzetme:
Senkron
Eğer bir arkadaşınıza bir telefon görüşmesi yapmak ve onu sizin için bir şey aramak için isteyin hayal edin. Biraz zaman alabilir olsa da, telefonda bekle ve arkadaşın sana gereken cevabı verir kadar uzaya bakıyor.
Aynı işlevi içeren bir arama yaptığınızda oluyor "" kod: . normal
function findItem() {
var item;
while(item_not_found) {
// search
}
return item;
}
var item = findItem();
// do something with item
doSomethingElse();
findItem
yürütmek için saat sürebilir rağmen, herhangi bir kod var item = findItem();
sonra geliyorbekleişlevi kadar sonuç döndürür.
Zaman uyumsuz
Arkadaşın aynı sebepten dolayı tekrar arayın. Ama bu sefer acelesi olduğunu ve gerektiğini söylesizi daha sonra ararımcep telefonunuzda. - Telefonu kapat, evden ve yapmayı planladığın her şeyi. Arkadaşın seni geri çağırır sonra, size verdiği bilgiler ile ilgileniyor.
Bu bir AJAX isteği ne zaman oluyor tam olarak.
findItem(function(item) {
// do something with item
});
doSomethingElse();
Cevap için beklemek yerine, yürütme hemen devam ediyor ve AJAX çağrısının ardından deyim yürütülür. Yanıt sonunda almak için, yanıtı aldıktan sonra çağrılacak bir işlev sağlargeri arama(bir şey fark ettin mi?Ara?). Herhangi bir açıklama çağrısının ardından gelen geri çağrılmadan önce yürütülür.
Çözüm(ler)
JavaScript asenkron doğayı kucaklayın!Belirli zaman uyumsuz işlemler senkron muadilleri sağlarken ("Ajax"), genellikle cesareti onları kullanmak için, özellikle tarayıcı bir bağlamda değil.
Neden kötü soruyorsun?
Tarayıcı UI iş parçacığı ve uzun süre çalışan işlem JavaScript çalışır UI, tepkisiz hale kilitlenir. Ayrıca, JavaScript yürütme zamanında bir üst sınır yoktur ve tarayıcı yürütme devam edip etmemek kullanıcıya sorar. Tüm bu gerçekten kötü bir kullanıcı deneyimi. Kullanıcı, her şeyin yolunda olup olmadığını söylemek mümkün olmayacaktır. Ayrıca etkisi yavaş bağlantısı olan kullanıcılar için daha kötü olacak.
Kod yeniden yapılandırılması
Fonksiyonları geri aramaları kabul edelim
Daha iyi bir yaklaşım kodunuzu geri etrafında düzgün bir şekilde organize etmektir. Söz konusu örnekte, success
geri arama foo
bir geri kabul ve kullanabilirsiniz. Bu yüzden bu
var result = foo();
// code that depends on 'result'
olur
foo(function(result) {
// code that depends on 'result'
});
Burada foo
argüman olarak bir fonksiyon geçiyoruz. Herhangi bir işlev başvurusu, örneğin geçirebilirsiniz:
function myCallback(result) {
// code that depends on 'result'
}
foo(myCallback);
foo
kendisi aşağıdaki gibi tanımlanır
function foo(callback) {
$.ajax({
// ...
success: callback
});
}
callback
diyoruz biz sadece success
aktarmak foo
geçişimizin işlevine bakın. I. e. bir zamanlar AJAX isteği başarılı, $.ajax
arama callback
ve geçiş yanıt için geri (ya da gönderilmesi result
beri bu şekilde tanımlı bir geri arama).
Ayrıca geri geçirmeden önce yanıt işleyebilir:
function foo(callback) {
$.ajax({
// ...
success: function(response) {
// e.g. filter the response
callback(filtered_response);
}
});
}
Daha kolay göründüğünden kodu geri çağrıları kullanarak yazıyorum. Sonuçta, tarayıcıda JavaScript tahrik (DOM olayları) ağır olay. AJAX yanıt almadan başka bir şey, bir olay.
Zorluklar üçüncü taraf kod ile çalışırken ortaya çıkabilir, ama çoğu sorun sadece uygulama akışı aracılığıyla düşünce tarafından çözülebilir.
Sözler kullanın
Promise API olduğunu ECMA yeni bir özellik) 6, ama iyi tarayıcı desteği zaten var. Ayrıca standart Söz API uygulamak ve ek yöntemler sağlayan birçok kütüphaneler asenkron fonksiyonlar (bluebird vs.) kullanımı ve kompozisyonu kolaylaştırmak için vardır.
Sözler için kapgelecekdeğerler. Ne zaman söz (. değeri alır ^em>çözüldüiptal edildiğinde ) veya (reddetti), " bu değer erişmek isteyenler var. "dinleyicileri onun bütün bildirir
Düz geri fazla fırsat kodunuzu ayrıştır onlar izin ve oluşturmak için daha kolay.
Burada bir söz kullanarak basit bir örnek:
function delay() {
// `delay` returns a promise
return new Promise(function(resolve, reject) {
// only `delay` is able to resolve or reject the promise
setTimeout(function() {
resolve(42); // after 3s, resolve the promise with value 42
}, 3000);
});
}
delay().then(function(v) { // `delay` returns a promise
console.log(v); // log the value once it is resolved
}).catch(function(v) {
// or do something else if it is rejected
// (would not happen in this example, since `reject` is not called
});
Ajax çağrısı uygulanan bu gibi sözler kullanın.
function ajax(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
resolve(this.responseText);
};
xhr.onerror = reject;
xhr.open('GET', url);
xhr.send();
});
}
ajax("/echo/json").then(function(result) {
// code depending on result
}).catch(function() {
// an error occurred
});
Teklif vaat eden tüm avantajlarını açıklayan bu cevap kapsamı dışındadır, ama eğer yeni bir kod yazarsanız, onları ciddi şekilde düşünmelisiniz. Kodunuz büyük bir soyutlama ve ayrılmasını sağlar.
Daha fazla bilgi vaatler hakkında: HTML5 rocks - JavaScript Promises
jQuery: ertelenmiş nesneleri Kullanın
Deferred objects jQuery özel uygulama ofpPromises Söz API standart önce (). Neredeyse vaat ediyor gibi davranır, ama biraz farklı bir API kullanır.
JQuery AJAX her yöntem zaten gelirler "ertelenmiş nesne" sadece dönüş (aslında ertelenmiş bir nesnenin bir söz) fonksiyonu:
function ajax() {
return $.ajax(...);
}
ajax().done(function(result) {
// code depending on result
}).fail(function() {
// an error occurred
});
Sorunlar söz
Sözler ve ertelenmiş nesneleri sadece olduğunu unutmayınkaplarbir gelecek için değer, değerin kendisi değildir. Örneğin, diyelim şu vardı:
function checkPassword() {
return $.ajax({
url: '/password',
data: {
username: $('#username').val()
password: $('#password').val()
},
type: 'POST',
dataType: 'json'
});
}
if (checkPassword()) {
// Tell the user they're logged in
}
Bu kod, yukarıda asenkronisi konularda yanlış anlamadan. Özellikle, $.ajax()
yok dondurma kodu süre denetler '/parola' sayfasında sunucu - bunun için bir istek gönderir, sunucu ve sırada bekler, hemen döner bir jQuery Ajax Ertelenmiş nesne değil, yanıt sunucudan. if
deyim kullanıcı oturumu sanki hep bu Ertelenmiş nesne almak, true
gibi davranıp devam edecek demektir. İyi değil.
Ama düzeltmek kolaydır:
checkPassword()
.done(function(r) {
if (r) {
// Tell the user they're logged in
} else {
// Tell the user their password was bad
}
})
.fail(function(x) {
// Tell the user something bad happened
});
Şimdi hala 'şifre' sunucu sayfasında, ama bizim kod artık düzgün sunucu yanıt vermek için beklemek zaman işler. /diyoruz $.ajax()
arama hemen jQuery Ajax Ertelenmiş bir nesne döndürür, ama .done()
.fail()
olay dinleyicileri eklemek için kullanıyoruz. Sunucu normal bir tepki (HTTP 200) ile cevap verdi .done()
arama, nesne sunucusu tarafından döndürülen kontrol ediyoruz. Bu örnekte sunucu eğer giriş başarılı, eğer yanlış değil, bu yüzden if (r)
true/denetleme yanlış ise doğru dönüyor.
.fail()
işleyicisi eğer kullanıcı kendi kullanıcı adı ve şifre yazmadan yaparken internet bağlantısı kaybolmuş veya sunucu aşağı giderse bir şeyler yanlış gidiyor ile ilgili örnek olacağız.
Tavsiye: "AJAX" diyor . Senkron
Bahsettiğim gibi, bazı zaman uyumsuz işlemler senkron karşılığı var. Orada kullanmak, bütünlüğü için bir savunucusu değilim iken, burada eşzamanlı bir arama gerçekleştirmek istiyorsunuz
Bir WordPress kullanmak olmadan
Eğer doğrudan XMLHTTPRequest
bir nesne kullanırsanız, 69* *üçüncü değişken olarak false
pass.
bir WordPress kullanmak
Eğer jQuery kullanıyorsanız async
55 ** seçeneği ayarlayabilirsiniz. Bu seçenek olduğunu unutmayınkaldırılmışjQuery 1.8 beri.
Sonra da hala success
bir geri arama kullanmak veya jqXHR object responseText
özelliği erişebilirsiniz:
function foo() {
var jqXHR = $.ajax({
//...
async: false
});
return jqXHR.responseText;
}
Eğer başka jQuery AJAX yöntemi kullanırsanız, $.get
, $.getJSON
gibi vs. $.ajax
değiştirmek için sadece $.ajax
yapılandırma parametreleri geçirebilirsiniz beri) var.
Başlar Yukarı!Mümkün JSONP senkron isteği yapmak için değil. Doğası gereği JSONP her zaman asenkron (hatta bu seçeneği düşünün için bir neden daha).
C 11 vadeli işlemler kullanarak: std ç...
'Görev arasındaki fark ne./Beklem...
Bir özel durum zaman uyumsuz bir yönte...
Nasıl Node.js zaman uyumsuz fonksiyonl...
Zaman uyumsuz/izleri bekliyor yığını...