Bir dizi jQuery Deferred ile nasıl çalışıyorsunuz?


132

Verilerin belirli bir sırayla yüklenmesini gerektiren bir uygulamam var: kök URL, ardından şemalar, ardından son olarak uygulamayı çeşitli veri nesneleri için şemalar ve URL'lerle başlat. Kullanıcı uygulamada gezinirken, veri nesneleri yüklenir, şemaya göre doğrulanır ve görüntülenir. Kullanıcı verileri CRUD'ladığında, şemalar ilk geçiş doğrulamasını sağlar.

Başlatma ile ilgili bir sorun yaşıyorum. Kök nesnesini ($ .when ()) getirmek için bir Ajax çağrısı kullanıyorum ve ardından her şema nesnesi için bir vaat dizisi oluşturuyorum. Bu işe yarıyor. Konsolda getirmeyi görüyorum.

Daha sonra tüm şemaların getirilmesini görüyorum, böylece her $ .ajax () çağrısı çalışıyor. fetchschemas () gerçekten de bir dizi vaat döndürür.

Ancak, bu son when () cümlesi hiçbir zaman ateşlenmez ve "DONE" kelimesi konsolda asla görünmez. Jquery-1.5'in kaynak kodu, () hiçbir nesne yoksa listeyi yönetmek için dahili bir Deferred () nesnesi oluşturduğunda olduğu gibi, $ .when.apply () 'ye geçirilecek bir nesne olarak "boş" un kabul edilebilir olduğunu ima ediyor gibi görünüyor. geçti.

Bu, Futures.js kullanılarak çalıştı. Böyle değilse, jQuery Ertelemeleri dizisi nasıl yönetilmelidir?

    var fetch_schemas, fetch_root;

    fetch_schemas = function(schema_urls) {
        var fetch_one = function(url) {
            return $.ajax({
                url: url,
                data: {},
                contentType: "application/json; charset=utf-8",
                dataType: "json"
            });
        };

        return $.map(schema_urls, fetch_one);
    };

    fetch_root = function() {
        return $.ajax({
            url: BASE_URL,
            data: {},
            contentType: "application/json; charset=utf-8",
            dataType: "json"
        });
    };

    $.when(fetch_root()).then(function(data) {
        var promises = fetch_schemas(data.schema_urls);
        $.when.apply(null, promises).then(function(schemas) {
            console.log("DONE", this, schemas);
        });
    });

"DONE" yazdırılmadan önce fetch_one'daki her ajax sorgusu için bir "başarılı" yöntemini çalıştırmam gerekmesi dışında neredeyse aynı bir problemim var. Bunu nasıl yapacaksın? "Fetch_one" dan sonra .pipe kullanmayı denedim ama işe yaramadı.
CambridgeMike

Yanıtlar:


198

Arıyorsun

$.when.apply($, promises).then(function(schemas) {
     console.log("DONE", this, schemas);
}, function(e) {
     console.log("My ajax failed");
});

Bu da işe yarayacak (belirli bir iş değeri için, bozuk ajax'ı düzeltmez):

$.when.apply($, promises).done(function() { ... }).fail(function() { ... });` 

Sen geçmek isteyeceksiniz $yerine nullböylece thisiçeride $.whenifade eder jQuery. Kaynak için önemli olmamalı ama geçmekten daha iyidir null.

İle değiştirerek tüm $ .ajax'ınızı taklit etti $.whenve örnek işler

Yani bu, ajax isteğinizde veya fetch_schemas'a geçirdiğiniz dizide bir sorun.


Teşekkür ederim. Bu sözdiziminin done (). Fail () 'den farkı nedir?
Elf Sternberg

2
@elf Sternberg, .then(a,b) === .done(a).fail(b)tembel bir kısaltma. Sen diyebilirsin .done(a).fail(b)istersen
Raynos

1
Oh, ve $ .when.apply ($, ...) ve $ .when.apply (null, ...) kullanımı alakasız görünüyor. jQuery'nin kendisinin bir promise () yöntemi yoktur, bu nedenle dahili olarak oluşturulan bir Ertelenmiş nesne (jQuery 1.5, satır 943) lehine göz ardı edilir.
Elf Sternberg

1
@ElfSternberg gerçekten alakasız, ancak okunabilirlik için ikinci bir göz atmam gerekmiyor $.when.apply($, .... nullGitmeme yapar "ne beklemek?". Bu bir stil ve kodlama pratiği meselesi. thisJQuery.when içine boş bir referans atmayacağından emin olmak için kaynağı okumak zorunda kaldım!
Raynos

7
Null kullanımı beni 'tamam, bu bir çeşit geçici çözüm' diye düşündürüyor (ki öyle), oysa $ kullanılırsa dikkatim $ 'ın wtf için olduğunu düşünmeye yöneltilirdi.
Danyal Aytekin

53

Yukarıdaki geçici çözüm (teşekkürler!), Ertelenmiş resolve()yöntemine sağlanan nesneleri geri alma sorununu doğru bir şekilde ele almıyor çünkü jQuery done()ve fail()geri aramalarını bir dizi değil, ayrı parametrelerle çağırıyor . Bu arguments, ertelemeler dizisi tarafından döndürülen tüm çözümlenmiş / reddedilmiş nesneleri almak için sözde diziyi kullanmamız gerektiği anlamına gelir , bu çirkin bir durumdur:

$.when.apply($, promises).then(function() {
     var schemas=arguments; // The array of resolved objects as a pseudo-array
     ...
};

Bir dizi ertelenmiş olarak geçtiğimiz için, bir dizi sonucu geri almak güzel olurdu. Ayrıca, sözde dizi yerine gerçek bir diziyi geri almak güzel olurdu, böylece Array.sort().

İşte esinlenerek bir çözümdür when.js 'ın when.all()yöntemine adresleri bu sorunların olduğu:

// Put somewhere in your scripting environment
if (jQuery.when.all===undefined) {
    jQuery.when.all = function(deferreds) {
        var deferred = new jQuery.Deferred();
        $.when.apply(jQuery, deferreds).then(
            function() {
                deferred.resolve(Array.prototype.slice.call(arguments));
            },
            function() {
                deferred.fail(Array.prototype.slice.call(arguments));
            });

        return deferred;
    }
}

Artık basitçe bir dizi ertelenmiş / vaat ekleyebilir ve geri çağrınızda bir dizi çözülmüş / reddedilmiş nesneyi geri alabilirsiniz, örneğin:

$.when.all(promises).then(function(schemas) {
     console.log("DONE", this, schemas); // 'schemas' is now an array
}, function(e) {
     console.log("My ajax failed");
});

@crispyduck - o zaman () içindeki "şemalar" değişkenindeki dizi öğelerinin sırasının her zaman "vaatler" değişkenindeki ajax çağrılarıyla aynı sırada olacağından% 100 emin olup olamayacağınızı biliyor musunuz? ()?
netpoetica

6
Bu sadece jQuery'de yerleşik olmalıdır, ancak - jQuery ekibi isteği birkaç kez reddetti. Bu arada, insanlar burada soruyu sormaya devam ediyor ve jQuery'ye karşı benzer biletler açıyorlar ve sonunda her yerde bir kullanıcı alanı uygulaması ve / veya apply()... şekle gitmek için garip çağrılarla karşılaşıyoruz .
mindplay.dk

Bu çözüm için teşekkürler! Bir (veya daha fazla) başarısız olduğunda da başarılı öğeleri almanın bir yolu var mı?
doktoreas

Burada yaptığınız tek şey arguments, kendi yöntemine gizlenmiş manipülasyon. Yeniden kullanım için harika, ancak başa çıkmak zorunda olmanın "çirkinliğine" hitap etmiyor arguments(kolayca şunları elde edebilirsiniz:var schemas=Array.prototype.slice.call(arguments);)
cowbert

2
@crispyduck, deferred.fail(...)okumalı deferred.reject(...)mı?
Bob S

19

Javascript'in ES6 sürümünü kullanıyorsanız Nesne dizisini virgülle ayrılmış bağımsız değişkenlere dönüştüren bir yayılma operatörü (...) vardır.

$.when(...promises).then(function() {
 var schemas=arguments; 
};

ES6 yayılma operatörü hakkında daha fazla bilgi https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator burada bulabilirsiniz


1
Evet. Bununla birlikte, Coffeescript veya onun soyundan / taklitçilerinden birini kullananlar bir süredir bu operatöre erişebiliyoruz.
Elf Sternberg

0

bu kodla ne zaman genişletilir:

var rawWhen = $.when
$.when = function(promise) {
    if ($.isArray(promise)) {
        var dfd = new jQuery.Deferred()
        rawWhen.apply($, promise).done(function() {
            dfd.resolve(Array.prototype.slice.call(arguments))
        }).fail(function() {
            dfd.reject(Array.prototype.slice.call(arguments))
        })
        return dfd.promise()
    } else {
        return rawWhen.apply($, arguments)
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.