SORU
8 Ocak 2013, Salı


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
8 Ocak 2013, Salı


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).

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • HTC

    HTC

    12 Ocak 2006
  • Liz Morgan

    Liz Morgan

    4 Aralık 2011
  • Ricardo Cerqueira

    Ricardo Cerq

    28 Mayıs 2008