ÖN ve SONRA yakanın yerleştirilmesi


105

.catchİç içe bir sözde ÖNCE ve SONRA koymak arasındaki farkı anlamakta güçlük çekiyorum .

Alternatif 1:

test1Async(10).then((res) => {
  return test2Async(22)
    .then((res) => {
      return test3Async(100);
    }).catch((err) => {
      throw "ERROR AFTER THEN";
    });
}).then((res) => {
  console.log(res);
}).catch((err) => {
  console.log(err);
});

Alternatif 2:

test1Async(10).then((res) => {
   return test2Async(22)
     .catch((err) => {
        throw "ERROR BEFORE THEN";
      })
      .then((res) => {
        return test3Async(100);
      });
  }).then((res) => {
    console.log(res);
  }).catch((err) => {
    console.log(err);
  });

Her işlevin davranışı aşağıdaki gibidir, sayı ise test1 başarısız olur, sayı ise <0test2 başarısız olur > 10ve sayı değilse test3 başarısız olur 100. Bu durumda test2 yalnızca başarısız olur.

Test2Async'i çalıştırmayı denedim ve hem ÖNCE hem de SONRA aynı şekilde davranıyor ve bu test3Async'i çalıştırmıyor. Biri bana avı farklı yerlere yerleştirmenin temel farkını açıklayabilir mi?

Her işlevde console.log('Running test X'), çalıştırılıp çalıştırılmadığını kontrol etmek için.

Bu soru, göndermiş olduğum önceki ileti dizisi nedeniyle ortaya çıkıyor. Yuvalanmış geri aramayı söze nasıl dönüştürebilirim? . Bunun farklı bir sorun olduğunu ve başka bir konuyu yayınlamaya değer olduğunu düşünüyorum.


hem .sonra hem de .catch, verilen sözü değiştirebilir ... bu yüzden yanlış anlamanın nereden geldiğinden emin değilim. Eğer .then'den önce catch koyarsanız, .then'den önce gerçekleşen retleri yakalar ve .then, .catch içinde olanlara göre bitti / başarısız geri aramalarını çalıştırır ve bunları değiştirdiğinizde bunun tersi de geçerlidir.
Kevin B

Sorum net değilse özür dilerim. Ama bu durumda dediğim gibi, her iki durum da aynı şekilde davranıyor bu yüzden farkı göremiyorum. Bana ne zaman ÖNCE yakalama yapacağımızı ve daha sonra ne zaman koymaya karar verdiğimizi söyleyebilir misiniz? sonrasına koymak gerçekten sezgisel ve yaygın görünüyor. Bazen neden daha önce koyduğumuzdan emin değilim
Zanko

Aynı şeyi yapıyorlarsa, bunun nedeni her birinin yaptığı şeyin bu özel durumda sonucu değiştirmemesidir. Her ikisinde de küçük bir değişiklik sonucu değiştirebilir.
Kevin B

"Sonucu değiştirmek" ne demek? Üzgünüm gerçekten
kafam karıştı

Örneğin, bir hata atmak yerine hiçbir şey yapmadıysanız, verilen söz reddedilmekten çözülmeye geçecektir. Bu elbette sonucu değiştirir, çünkü söz artık reddedilmiş değil, kararlı bir sözdür. (tabii ki çözülmediyse, bu durumda yakalama zaten çalışmazdı)
Kevin B

Yanıtlar:


242

Yani, temelde bu ikisi arasındaki farkın ne olduğunu soruyorsunuz (burada pönceki bazı kodlardan oluşturulan bir söz var):

return p.then(...).catch(...);

ve

return p.catch(...).then(...);

P çözdüğünde veya reddettiğinde farklılıklar vardır, ancak bu farklılıkların önemli olup olmadığı .then()veya .catch()işleyiciler içindeki kodun ne yaptığına bağlıdır .

pÇözüldüğünde ne olur :

İlk şemada, pçözüldüğünde, .then()işleyici çağrılır. Bu .then()işleyici bir değer veya sonunda çözülen başka bir söz döndürürse, .catch()işleyici atlanır. Ancak, .then()işleyici sonunda reddeden bir söz atar veya döndürürse, .catch()işleyici hem orijinal sözdeki bir ret için hem pde .then()işleyicide oluşan bir hata için yürütür .

İkinci şemada, pçözüldüğünde, .then()işleyici çağrılır. Bu .then()işleyici, sonunda reddeden bir söz atar veya döndürürse, .catch()işleyici bunu yakalayamaz çünkü zincirde önündedir.

Yani bu 1 numaralı fark. .catch()İşleyici SONRA ise, işleyicinin içindeki hataları da yakalayabilir .then().

pReddedildiğinde ne olur :

Şimdi, ilk şemada, eğer söz preddederse, o zaman .then()işleyici atlanır ve .catch()beklediğiniz gibi işleyici çağrılır. Ne yapmak .catch()işleyici nihai sonuç olarak döndürülür belirler. Yalnızca .catch()işleyiciden bir değer döndürürseniz veya sonunda çözülen bir söz verirseniz, söz verme zinciri çözülmüş duruma geçer çünkü siz hatayı "ele alıp normal şekilde geri döndünüz". Uygulayıcıda reddedilen bir sözü verir veya geri verirseniz .catch(), iade edilen söz reddedilmiş olarak kalır.

İkinci şemada, söz preddedilirse, .catch()işleyici çağrılır. Eğer normal bir değer veya sonunda .catch()işleyiciden çözülen bir vaat döndürürseniz (böylece hatayı "ele alır"), vaat zinciri çözümlenmiş duruma geçer ve çağrıldıktan .then()sonra işleyici işleyiciye geçer .catch().

Yani bu 2 numaralı fark. Eğer .catch()işleyici ÖNCE olduğunu, o zaman hatayı işlemek ve izin verebilir .then()işleyici hala etmelerini sağlamak.

Hangisi ne zaman kullanılır:

.catch()Ya orijinal sözdeki pya da .then()işleyicideki hataları yakalayabilen tek bir işleyici istiyorsanız, ilk şemayı kullanın ve bir reddinin işleyiciyi patlaması gerekir .then().

İlk sözdeki hataları yakalayabilmek istiyorsanız ikinci şemayı kullanın pve belki (koşullara bağlı olarak), söz zincirinin çözülmüş olarak devam etmesine izin verin, böylece .then()işleyiciyi çalıştırın .

Diğer seçenek

Her iki geri aramayı kullanmak için de olduğu .then()gibi geçirebileceğiniz bir seçenek daha var :

 p.then(fn1, fn2)

Bu, yalnızca birinin aranacağını fn1veya aranacağını garanti eder fn2. Eğer pgiderir, sonra fn1çağrılır. Eğer preddeder, o zaman fn2çağrılır. Sonuçtaki hiçbir değişiklik fn1asla fn2aranamaz veya tersi olamaz . Öyleyse, işleyicilerin kendisinde ne olursa olsun, iki işleyicinizden yalnızca birinin çağrıldığından kesinlikle emin olmak istiyorsanız, kullanabilirsiniz p.then(fn1, fn2).


19
Soru, özellikle sizin .then()ve yanıtladığınız sırayla ilgilidir .catch(). Buna ek olarak, hangi sırayı ne zaman kullanacağınıza dair bazı ipuçları veriyorsunuz, bence üçüncü bir seçenekten bahsetmenin uygun olduğunu, yani hem başarı hem de hata işleyiciyi .then () 'e geçirmek . Bu durumda en fazla bir işleyici çağrılacaktır.
ArneHugo

9
@ArneHugo - İyi bir öneri. Ekledim.
jfriend00

Öyleyse, Söz Zinciri Oluşturma sırasında, sonra .catch .catch. Ve sonra tür senaryolar yazabilir miyiz?
Kapil Raghuwanshi

@KapilRaghuwanshi, evet, başarısızlık durumunda varsayılan bir değeri geçirmek için kullanabilirsiniz. yani Promise.reject(new Error("F")).then(x => x).catch(e => {console.log(e); return [1]}).then(console.log)ve Promise.resolve([2]).then(x => x).catch(e => [1]).then(console.log)
CervEd

1
@DmitryShvedov - Tahmin ettiğim gibi, bu yanlış .then(this.setState({isModalOpen: false})). .then()Parenlerdeki kodun hemen çalıştırılması için (söz çözülmeden önce) bir işlev başvurusu iletmiyorsunuz. Olmalı .then(() => this.setState({isModalOpen: false})).
jfriend00

32

jfriend00'ün cevabı mükemmel, ancak analog senkron kodu eklemenin iyi bir fikir olacağını düşündüm.

return p.then(...).catch(...);

senkronize olana benzer:

try {
  iMightThrow() // like `p`
  then()
} catch (err) {
  handleCatch()
}

Eğer iMightThrow()atmaz, then()çağrılacak. Fırlatırsa (veya then()kendisi atarsa), o handleCatch()zaman çağrılacaktır. catchBloğun thençağrılıp çağrılmayacağı üzerinde nasıl bir kontrolü olmadığına dikkat edin .

Diğer yandan,

return p.catch(...).then(...);

senkronize olana benzer:

try {
  iMightThrow()
} catch (err) {
  handleCatch()
}

then()

Bu durumda, iMightThrow()atmazsa then()çalıştırır. Eğer fırlatırsa, o zaman çağrılıp çağrılmayacağına handleCatch()karar vermek gerekir then(), çünkü eğer handleCatch()yeniden then()atılırsa, istisna hemen arayana atılacağından çağrılmayacaktır. Eğer handleCatch()incelikle sorunu işleyebilir, daha sonra then()adı verilecek.


bu iyi bir açıklama, ancak yetimi then()finally{...}
2018'de

2
@ 82Tuskers, Emin misin? Ben koyarsam then()içinde finally{...}, yanlış bile çağrılmayacaktı handleCatch()atar?
Amacımın,

Yani, tüm durumları ele almak istiyorsak, ancak yine de .sonra () kullanmak en iyisi olur. Sonra (bir şeyler yapın) .catch (günlük hatası ve güncelleme durumu). Sonra (başka bir şey yapın) .catch (günlük hatası) her noktada yakalamaya çalıştığımız ama aynı zamanda stmnts'i yürütmeye devam ettiğimiz yer?
anna
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.