JQuery ertelenmiş'in “o zaman” yöntemini ne zaman ve “boru” yöntemini ne zaman kullanmalıyım?


97

jQuery'nin Deferredeşzamansız işlev zincirlemesini uygulamak için kullanılabilecek iki işlevi vardır:

then()

deferred.then( doneCallbacks, failCallbacks ) Returns: Deferred

doneCallbacks Ertelenmiş çözümlendiğinde çağrılan bir işlev veya işlevler dizisi.
failCallbacks Ertelenmiş reddedildiğinde çağrılan bir işlev veya işlevler dizisi.

pipe()

deferred.pipe( [doneFilter] [, failFilter] ) Returns: Promise

doneFilter Ertelenmiş çözümlendiğinde çağrılan isteğe bağlı bir işlev.
failFilter Ertelendi reddedildiğinde çağrılan isteğe bağlı bir işlev.

Bundan then()biraz daha uzun süredir ortalıkta olduğunu biliyorum , pipe()ikincisi biraz ekstra fayda sağlamalı, ancak fark tam olarak beni kaçırıyor. Her ikisi de hemen hemen aynı geri arama parametrelerini alırlar, ancak isimleri farklıdır ve a Deferreddöndürme ile a döndürme arasındaki fark Promiseküçük görünür.

Resmi belgeleri defalarca okudum, ancak her zaman kafamı dolaştırmak için onları çok "yoğun" buldum ve arama, bir özelliğin veya diğerinin birçok tartışmasını buldu, ancak farklı olanı gerçekten açıklığa kavuşturan hiçbir şey bulamadım her birinin artıları ve eksileri.

Peki ne zaman kullanmak daha iyidir thenve ne zaman kullanmak daha iyidir pipe?


İlave

Felix'in mükemmel cevabı , bu iki işlevin nasıl farklılaştığını netleştirmeye gerçekten yardımcı oldu. Ancak, işlevselliğinin bunun yerine then()tercih edilebilir olduğu zamanlar olup olmadığını merak ediyorum pipe().

Bundan pipe()daha güçlü olduğu aşikar then()ve görünen o ki, birincisi ikincisinin yapabileceği her şeyi yapabilir. Kullanmanın bir nedeni then(), adının aynı verileri işleyen bir işlevler zincirinin sonlandırılması rolünü yansıtması olabilir.

Ancak then()orijinalin yenisini iade etmesi nedeniyle Deferredyapılamayacak şekilde iade edilmesini gerektiren bir kullanım durumu var mı?pipe()Promise


1
Bunu bir süre düşündüm ama tbh, herhangi bir kullanım durumu düşünemiyorum. İhtiyaç duymuyorsanız yeni vaat nesneleri oluşturmak ek yük olabilir (dahili olarak nasıl zincirlendiklerini bilmiyorum). Bununla birlikte, bunu kesinlikle benden daha iyi anlayan insanlar var.
Felix Kling

6
Bu soruyla ilgilenen herkes, jQuery hata izleyicisindeki Bilet # 11010 ile kesinlikle ilgilenecektir: ERTELENMEYİN.THEN == ERTELENMİŞ BORU GİBİ PROMISE / A
hippietrail

Yanıtlar:


103

Yana jQuery 1.8 .then ile aynı şekilde davranır .pipe:

Kullanımdan Kaldırma Bildirimi: jQuery 1.8'den itibaren, deferred.pipe()yöntem kullanımdan kaldırılmıştır. Onun deferred.then()yerine geçen yöntem kullanılmalıdır.

ve

JQuery 1.8'den itibaren , deferred.then()yöntem, artık kullanımdan kaldırılan deferred.pipe()yöntemin yerini alarak, bir işlev aracılığıyla ertelenmiş bir işlemin durumunu ve değerlerini filtreleyebilen yeni bir taahhüt döndürür .

Aşağıdaki örnekler yine de bazıları için yardımcı olabilir.


Farklı amaçlara hizmet ederler:

  • .then()Sürecin sonucuyla çalışmak istediğinizde, yani belgelerin dediği gibi, ertelenen nesne çözüldüğünde veya reddedildiğinde kullanılacaktır. .done()Veya kullanmakla aynıdır .fail().

  • Sonucu bir .pipe()şekilde (önceden) filtrelemek için kullanırsınız. Bir geri aramanın dönüş değeri .pipe(), doneve failgeri aramalarına bağımsız değişken olarak iletilecektir . Ayrıca başka bir ertelenmiş nesneyi de döndürebilir ve aşağıdaki geri aramalar bu ertelenen üzerine kaydedilecektir.

    Bu, .then()(veya .done(), .fail()) durumunda geçerli değildir, kayıtlı geri aramaların dönüş değerleri sadece göz ardı edilir.

Yani, ya .then() da kullanman değil.pipe() . Sen olabilir kullanmak .pipe()gibi aynı amaçla .then()ama tersi tutmaz.


örnek 1

Bazı işlemlerin sonucu bir nesneler dizisidir:

[{value: 2}, {value: 4}, {value: 6}]

ve minimum ve maksimum değerleri hesaplamak istiyorsunuz. İki donegeri arama kullandığımızı varsayalım :

deferred.then(function(result) {
    // result = [{value: 2}, {value: 4}, {value: 6}]

    var values = [];
    for(var i = 0, len = result.length; i < len; i++) {
        values.push(result[i].value);
    }
    var min = Math.min.apply(Math, values);

   /* do something with "min" */

}).then(function(result) {
    // result = [{value: 2}, {value: 4}, {value: 6}]

    var values = [];
    for(var i = 0, len = result.length; i < len; i++) {
        values.push(result[i].value);
    }
    var max = Math.max.apply(Math, values);

   /* do something with "max" */ 

});

Her iki durumda da listeyi yinelemeniz ve her nesneden değeri çıkarmanız gerekir.

Her iki geri aramada da bunu ayrı ayrı yapmak zorunda kalmamak için değerleri önceden bir şekilde çıkarmak daha iyi olmaz mıydı? Evet! Ve bunun .pipe()için kullanabiliriz :

deferred.pipe(function(result) {
    // result = [{value: 2}, {value: 4}, {value: 6}]

    var values = [];
    for(var i = 0, len = result.length; i < len; i++) {
        values.push(result[i].value);
    }
    return values; // [2, 4, 6]

}).then(function(result) {
    // result = [2, 4, 6]

    var min = Math.min.apply(Math, result);

    /* do something with "min" */

}).then(function(result) {
    // result = [2, 4, 6]

    var max = Math.max.apply(Math, result);

    /* do something with "max" */

});

Açıkçası bu uydurma bir örnek ve bu sorunu çözmenin birçok farklı (belki daha iyi) yolu var, ama umarım bu noktayı açıklar.


Örnek 2

Ajax aramalarını düşünün. Bazen bir önceki arama tamamlandıktan sonra bir Ajax çağrısı başlatmak istersiniz. Bunun bir yolu, ikinci aramayı bir donegeri arama içinde yapmaktır :

$.ajax(...).done(function() {
    // executed after first Ajax
    $.ajax(...).done(function() {
        // executed after second call
    });
});

Şimdi, kodunuzu ayırmak ve bu iki Ajax çağrısını bir işlevin içine koymak istediğinizi varsayalım:

function makeCalls() {
    // here we return the return value of `$.ajax().done()`, which
    // is the same deferred object as returned by `$.ajax()` alone

    return $.ajax(...).done(function() {
        // executed after first call
        $.ajax(...).done(function() {
            // executed after second call
        });
    });
}

Ertelenmiş nesneyi makeCalls, ikinci Ajax çağrısı için geri çağrılar eklemeyi çağıran diğer koda izin vermek için kullanmak istiyorsunuz , ancak

makeCalls().done(function() {
    // this is executed after the first Ajax call
});

İkinci arama bir donegeri arama içinde yapıldığından ve dışarıdan erişilemediğinden istenen etkiyi yaratmayacaktır .

Çözüm .pipe()bunun yerine kullanmak olacaktır :

function makeCalls() {
    // here we return the return value of `$.ajax().pipe()`, which is
    // a new deferred/promise object and connected to the one returned
    // by the callback passed to `pipe`

    return $.ajax(...).pipe(function() {
        // executed after first call
        return $.ajax(...).done(function() {
            // executed after second call
        });
    });
}

makeCalls().done(function() {
    // this is executed after the second Ajax call
});

Kullanarak .pipe(), artık çağrıların gerçek akışını / sırasını göstermeden geri aramaları "iç" Ajax çağrısına eklemeyi mümkün kılabilirsiniz.


Genel olarak, ertelenmiş nesneler, kodunuzu ayırmanın ilginç bir yolunu sağlar :)


Ah evet pipe, yapamayan filtreleme yapabileceğini gözden kaçırdım then. Ancak Googling'de bu konulara pipegöre filter, filtrelemenin kendisiyle birlikte gelen bir ekstra ekstra bir şey olduğu düşünülürse pipede gerçek amacını daha açık bir şekilde gösterdiği için onu adlandırmayı seçtiler . Görünüşe göre filtrelemenin yanı sıra başka farklılıklar da olmalı. (Sonra tekrar ben gerçekten hatta örneklerle filtreleme özelliği anlamıyorum itiraf mı. result values;Olmak return values;arada?)
hippietrail

Örneklerinizi anlamadığımı söylediğimde, bu şöyle bir şey mi: Üstteki örnekte, ikisi her seferinde filtrelediğiniz .then()aynı verileri alır result; oysa alt örnekte, sonraki iki s alacağı için bunu iletmeden önce .pipe()içindeki verilerin bir kısmını kaldırır. resultresult.then()
hippietrail

1
@hippietrail: Bu arada cevabımı güncelledim ve diğer amaçlara da yer verdim .pipe(). Geri arama ertelenmiş bir nesne döndürürse, daha sonra yapılan veya başarısız olan geri aramalar bu nesne için kaydedilir. Başka bir örnek ekleyeceğim. düzenleme: ikinci yorumunuzla ilgili olarak: evet.
Felix Kling

Yani tek fark bu veri akışlarını olduğu aracılığıyla pipe() oysa then()daha bir gibi yaprak düğümü olmasına rağmen size verilerini kullanmak zorunda olduğu sonunda ve ileride akmaz ve bu then()duruma göre bir Deferredaslında / kullanışlı kullanılmaz? Eğer bu doğruysa /* do something with "min"/"max" */, her ".then () cümlesine" benzer bir şey eklemenin açıklığa kavuşturulması yardımcı olabilir .
hippietrail

1
Endişelenmeyin :) Ertelenmiş nesnelerin ve yöntemlerinin nasıl çalıştığını tam olarak anlamak da biraz zaman aldı. Ama bir kez anladığınızda, artık zor görünmüyor. Belgelerin muhtemelen daha kolay bir şekilde yazılabileceğini kabul ediyorum.
Felix Kling

7

then()Üzerinde kullanmanız GEREKEN bir durum yok pipe(). Her zaman pipe()geçecek değeri görmezden gelmeyi seçebilirsiniz . Kullanmak için küçük bir performans darbesi olabilirpipe - ancak önemli olması olası değildir.

Bu nedenle, her zaman her pipe()iki durumda da kullanabileceğiniz gibi görünebilir . Bununla birlikte , kullanarak pipe(), kodunuzu okuyan diğer insanlara (bundan altı ay sonra kendiniz de dahil olmak üzere) dönüş değerinin bir miktar önemi olduğunu iletiyorsunuz. Eğer onu atarsanız, bu anlamsal yapıyı ihlal etmiş olursunuz.

Asla kullanılmayan bir değer döndüren bir işleve sahip olmak gibidir: kafa karıştırıcı.

Öyleyse then()ne zaman ve pipe()ne zaman yapman gerektiğini kullan ...


3
K. Scott Allen'ın "Experiments In Writing" blogundaki ikisini kullanarak gerçek hayattan bir örnek buldum: Geolocation, Geocoding ve jQuery Promises : "O zaman kontrol mantığı oldukça iyi okur:" $(function () { $.when(getPosition()) .pipe(lookupCountry) .then(displayResults); }); "Borunun, çünkü boru yeni bir söz veriyor. "
hippietrail

5

Aslında arasındaki fark çıkıyor .then()ve .pipe()gereksiz kabul edilmiştir ve onlar jQuery sürümü 1.8 ile aynı olacak şekilde yapılmıştır.

Gönderen tarafından bir açıklamajaubourg jQuery'nin hata izleyici içinde bilet # 11010 "MARKA DEFERRED.THEN == DEFERRED.PIPE GİBİ SÖZÜMÜZ / A":

1.8'de eskisini kaldırıp mevcut boruyla değiştireceğiz. Ancak çok üzücü sonuç, insanlara standart dışı bitmiş, başarısız ve ilerlemeyi kullanmalarını söylememiz gerekecek, çünkü teklif basit, ETKİLİ, sadece bir geri arama eklemek için bir araç sağlamıyor.

(vurgu benim)


1
Şimdiye kadarki en iyi referans, gelişmiş kullanımları arıyorum.
TWiStErRob
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.