.Then (başarı, başarısız) ne zaman vaatler için bir karşıtlık olarak kabul edilir?


188

Ben bir göz vardı bluebird söz SSS o bahseder ettiği, .then(success, fail)bir antipattern olduğunu . Denemek ve yakalamak için açıklamasını tam olarak anlamıyorum. Bunun nesi yanlış?

some_promise_call()
.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })

Örnek şu şekilde doğru yolu önermektedir.

some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })

Fark ne?


1
then().catch()virgül ve araştırmaya gerek duymadığınız için daha okunabilirdir.
Krzysztof Safjanowski

7
@KevinB: Çok fazla fark var, cevapları kontrol edin
Bergi

12
@KrzysztofSafjanowski - 'daha iyi görünüyor' argümanı tarafından harap edildi. Tamamen yanlış!
Andrey Popov

6
NOT: Kullanırken .catch, hangi adımın soruna neden olduğunu bilmiyorsunuz - son thenveya başka bir yerde vaat zincirinin içinde. Yani kendi dezavantajı var.
vitaly-t

2
Ben her zaman vaat .then () params okunabilir hale getirmek için işlev adları ekleyinsome_promise_call() .then(function fulfilled(res) { logger.log(res) }, function rejected(err) { logger.log(err) })
Shane Rowatt

Yanıtlar:


216

Fark ne?

.then()Çağrı geri arama bir hata atar durumda reddedilecek bir söz dönecektir. Bu, başarınız loggerbaşarısız olduğunda, hatanın aşağıdaki .catch()geri aramaya iletileceği , ancak failyan yana gelen geri aramaya geçilmeyeceği anlamına gelir success.

İşte bir kontrol akış şeması:

akış diyagramı ve sonra iki argüman sonra zincir yakalamak kontrol akış diyagramı

Senkronize kodda ifade etmek için:

// some_promise_call().then(logger.log, logger.log)
then: {
    try {
        var results = some_call();
    } catch(e) {
        logger.log(e);
        break then;
    } // else
        logger.log(results);
}

İkincisi log(ilk argüman gibi .then()) yalnızca istisna olmaması durumunda yürütülür. Etiketli blok ve breakifade biraz garip hissediyorum, aslında python try-except-elseiçin olan budur (önerilen okuma!).

// some_promise_call().then(logger.log).catch(logger.log)
try {
    var results = some_call();
    logger.log(results);
} catch(e) {
    logger.log(e);
}

catchKaydedicisi de başarı logger çağrısından istisnalar işleyecektir.

Fark için çok fazla.

Denemek ve yakalamak için açıklamasını tam olarak anlamıyorum

Argüman, genellikle işlemenin her adımında hata yakalamak istediğiniz ve bunu zincirlerde kullanmamanızdır. Beklenti, tüm hataları işleyen yalnızca bir son işleyiciniz olması - "karşıt nokta" yı kullandığınızda, o zaman geri çağrıların bazılarındaki hatalar işlenmez.

Ancak, bu desen gerçekten çok yararlıdır: Tam olarak bu adımda meydana gelen hataları işlemek istediğinizde ve hata olmadığında tamamen farklı bir şey yapmak istediğinizde (yani hata kurtarılamaz olduğunda). Unutmayın bu olduğunu dallanma kontrol akışını. Tabii ki, bu bazen istenir.


Bunun nesi yanlış?

some_promise_call()
.then(function(res) { logger.log(res) }, function(err) { logger.log(err) })

Geri aramanızı tekrarlamanız gerektiğini. İstiyorsun

some_promise_call()
   .catch(function(e) {
       return e; // it's OK, we'll just log it
   })
   .done(function(res) {
       logger.log(res);
   });

Bunun .finally()için kullanmayı da düşünebilirsiniz .


7
bu birkaç gün içinde okuduğum en yararlı açıklama (ve çok okudum). Ne kadar minnettar olduğumu açıklayamam! :) Ben ikisi arasındaki daha farkını stres gerektiğini düşünüyorum .catchedecektir bile başarı işlevi içinde hataları yakalamak .. Şahsen ben son derece yanlış sizden birden fazla hata alabilirsiniz bir hata giriş noktasında, ile bitirmek olarak bu bulmak birden fazla eylem, ama bu benim sorunum. Neyse - bilgi için teşekkürler! Paylaşmak istediğiniz çevrimiçi iletişim aracınız yok, bu yüzden birkaç şey daha isteyebilir miyim? : P
Andrey Popov

2
Umarım bu size biraz daha oy verir. Kesinlikle Promisebu sitede önemli bir tamircinin en iyi açıklamalarından biri .
Patrick Roberts

2
.done()standardın bir parçası değil, değil mi? En azından MDN bu yöntemi listelemiyor. Yardımcı olur.
ygoe

1
@ygoe Gerçekten. donetemel olarak then+ işlenmeyen ret algılaması tarafından kullanımdan kaldırılan bir Bluebird şeyidir.
Bergi

1
bir renk körlüğünden sadece bir not: diyagramlar mantıklı değil :)
Benny K

37

İkisi de aynı değil. Fark, ilk örneğin, successişleyicinize atılan bir istisnayı yakalamamasıdır . Bu nedenle, yönteminizin yalnızca çözülmüş vaatler döndürmesi gerekiyorsa, çoğu zaman olduğu gibi, sondaki bir catchişleyiciye (veya thenboş bir successparametreye sahip başka birine) ihtiyacınız vardır. Elbette, thenişleyicinizin potansiyel olarak başarısız olabilecek herhangi bir şey yapmaması olabilir, bu durumda bir 2 parametresi kullanmak theniyi olabilir.

Ancak, bağlandığınız metnin thenasıl amacının, çoğu zaman eşzamansız adımları zincirleme yeteneğinde çoğunlukla geri çağrılara karşı faydalı olduğuna inanıyorum ve bunu yaptığınızda, 2 parametreli thenincelik biçimi beklendiği gibi davranmıyor , yukarıdaki nedenle. Orta zincir kullanıldığında özellikle mantıksızdır.

Bir sürü karmaşık asenkron malzeme yapan ve itiraf ettiğimden daha fazla bu gibi köşelere çarpan biri olarak, bu anti-modelden kaçınmayı ve ayrı işleyici yaklaşımıyla gitmeyi gerçekten tavsiye ederim.


18

Her ikisinin de avantajlarına ve dezavantajlarına bakarak, duruma uygun olan hesaplanmış bir tahmin yapabiliriz. Bunlar vaatlerin uygulanmasına yönelik iki ana yaklaşımdır. Her ikisinin de artıları ve eksi var

Yakalama Yaklaşımı

some_promise_call()
.then(function(res) { logger.log(res) })
.catch(function(err) { logger.log(err) })

Avantajları

  1. Tüm hatalar bir catch bloğu tarafından işlenir.
  2. Hatta o zaman blokta herhangi bir istisna yakalar.
  3. Birden çok başarılı geri arama zincirinin zincirlenmesi

Dezavantajları

  1. Zincirleme durumunda farklı hata mesajları göstermek zorlaşır.

Başarı / Hata Yaklaşımı

some_promise_call()
.then(function success(res) { logger.log(res) },
      function error(err) { logger.log(err) })

Avantajları

  1. İnce taneli hata kontrolü elde edersiniz.
  2. Db hatası, 500 hatası gibi çeşitli hata kategorileri için yaygın hata işleme işlevine sahip olabilirsiniz.

dezavantajlarını

  1. catchBaşarılı geri aramayla atılan hataları işlemek istiyorsanız yine bir başkasına ihtiyacınız olacak

Üretim sorunlarını yalnızca bir günlük dosyası kullanarak hata ayıklaması gereken biri için, uygulamanızın çıkış sınırlarında günlüğe kaydedilebilen nedensel bir hata zinciri oluşturma yeteneği sağladığı için Başarı / Hata Yaklaşımı'nı tercih ederim.
Shane Rowatt

soru. Diyelim ki birkaç şeyden birini yapan bir zaman uyumsuz çağrı yapıyorum: 1) başarıyla döndürür (2xx durum kodu), 2) başarısız döndürür (4xx veya 5xx kodu), ancak kendi başına reddedilmez, 3) veya hiç geri dönmez ( İnternet bağlantısı kesildi). Durum # 1 için, .then'deki başarılı geri arama vurulur. Durum # 2 için, .then içindeki hata geri çağırma vurulur. Durum 3 için .catch çağrılır. Bu doğru analiz, değil mi? Durum # 2 en zor m.ö. teknik olarak bir 4xx veya 5xx bir reddetme değildir, yine de başarıyla geri döner. Bu nedenle, .then içinde ele almamız gerekiyor. .... Anladığım doğru mu?
Benjamin Hoffman

Msgstr "" # 2 için, .then'deki hata geri çağrısı vuruldu. # 3 için .catch çağrıldı. Bu doğru analiz, değil mi? " - Getirme bu şekilde çalışır
aWebDeveloper

2

Basit açıklama:

ES2018'de

Catch yöntemi onRejected parametresiyle çağrıldığında aşağıdaki adımlar uygulanır:

  1. Söz ver bu değer olsun.
  2. Dönüş ? Çağırın (söz veriyorum, "sonra", «undefined, onRedected»).

bunun anlamı:

promise.then(f1).catch(f2)

eşittir

promise.then(f1).then(undefiend, f2)

1

Kullanarak bir iş akışını gerçekleştirmek için gereken Promise Chaining'i.then().catch() etkinleştirebilirsiniz . Veritabanından bazı bilgileri okumanız gerekebilir, ardından bir async API'sine aktarmak ve ardından yanıtı değiştirmek isteyebilirsiniz. Yanıtı veritabanına geri göndermek isteyebilirsiniz. Tüm bu iş akışlarını konseptinizle ele almak yapılabilir ancak yönetimi çok zordur. Daha iyi bir çözüm, tüm hataları sadece bir kez yakalamada alır ve kodun korunmasını sağlar .then().then().then().then().catch()


0

Kullanmak then()ve catch()zincir başarı ve başarısızlık işleyici söz üzerinde yardımcı olur. catch()tarafından verilen söz üzerinde çalışır then(). İşliyor,

  1. Söz reddedilirse. Resimdeki 3 numaralı resme bakın
  2. Then () öğesinin başarı işleyicisinde hata oluşursa, aşağıdaki 4 ile 7 arasındaki satır numaraları arasında. Resimdeki 2.a bölümüne bakın (Arıza geri çağırma açıkken then()bunu yapmaz.)
  3. Then () hata işleyicisinde hata oluşursa, aşağıdaki 8 numaralı satır. Resimdeki 3.b bölümüne bakınız.

1. let promiseRef: Promise = this. aTimetakingTask (false); 2. promiseRef 3. .then( 4. (result) => { 5. /* successfully, resolved promise. 6. Work on data here */ 7. }, 8. (error) => console.log(error) 9. ) 10. .catch( (e) => { 11. /* successfully, resolved promise. 12. Work on data here */ 13. });

resim açıklamasını buraya girin

Not : Çoğu zaman, catch()önceden yazılmışsa hata işleyici tanımlanamayabilir . DÜZENLEME: reject()çağrılırken sonucu catch()hata işleyicisi yalnızca then()edilir değil tanımlanmış. Resimdeki 3 numaralı uyarı catch(). 8. ve 9. satırdaki işleyici tanımlanmadığında çağrılır.

Bu mantıklıdır çünkü then()bir geri arama ilgileniyorsa, döndürülen sözün bir hatası yoktur.


3 numaradan catchgeri aramaya kadar olan ok yanlış görünüyor.
Bergi

Teşekkürler! Then () öğesinde tanımlanan bir hata geri çağrısıyla çağrılmaz (kod snippet'inde # 8 ve # 9 satırları). # 3 iki oktan birini çağırır. Bu mantıklıdır çünkü then () tarafından döndürülen sözün geri arama ile ilgileniyorsa bir hatası yoktur. Cevabı düzenledi!
VenCKi

-1

Kelimeler yerine iyi bir örnek. Aşağıdaki kod (eğer ilk söz çözülmüşse):

Promise.resolve()
.then
(
  () => { throw new Error('Error occurs'); },
  err => console.log('This error is caught:', err)
);

ile aynıdır:

Promise.resolve()
.catch
(
  err => console.log('This error is caught:', err)
)
.then
(
  () => { throw new Error('Error occurs'); }
)

Ancak reddedilen ilk sözle, bu aynı değildir:

Promise.reject()
.then
(
  () => { throw new Error('Error occurs'); },
  err => console.log('This error is caught:', err)
);

Promise.reject()
.catch
(
  err => console.log('This error is caught:', err)
)
.then
(
  () => { throw new Error('Error occurs'); }
)

4
Bu mantıklı değil, lütfen bu cevabı kaldırabilir misiniz? Yanıltıcı ve doğru cevaptan uzaklaşıyor.
Andy Ray

@AndyRay, bu gerçek uygulamada mantıklı değil, ancak sözlerin çalışmalarını anlamak mantıklı.
ktretyak
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.