Erken çözümden / reddetmeden sonra geri dönmem gerekir mi?


262

Aşağıdaki kodu aldığımı varsayalım.

function divide(numerator, denominator) {
 return new Promise((resolve, reject) => {

  if(denominator === 0){
   reject("Cannot divide by 0");
   return; //superfluous?
  }

  resolve(numerator / denominator);

 });
}

rejectAmacım erken çıkmak için kullanmaksa return, hemen sonra da ing alışkanlığına girmeli miyim ?


5
Evet, tamamlama

Yanıtlar:


371

returnAmaç reddi sonra fonksiyonunun uygulanmasını sona erdirme ve ondan sonra kod yürütülmesini önlemek içindir.

function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {

    if (denominator === 0) {
      reject("Cannot divide by 0");
      return; // The function execution ends here 
    }

    resolve(numerator / denominator);
  });
}

Bu durumda resolve(numerator / denominator);, kesinlikle gerekli olmayan çalıştırılmasını engeller . Bununla birlikte, gelecekte olası bir tuzağı önlemek için yürütmeyi sonlandırmak hala tercih edilir. Ayrıca, kodun gereksiz yere çalıştırılmasını önlemek için iyi bir uygulamadır.

Arka fon

Bir söz 3 durumdan birinde olabilir:

  1. bekleyen - başlangıç ​​durumu. Beklemeden diğer eyaletlerden birine geçebiliriz
  2. yerine getirildi - başarılı operasyon
  3. reddedildi - başarısız işlem

Bir söz yerine getirildiğinde veya reddedildiğinde, bu durumda süresiz olarak kalır (kararlaştırılır). Dolayısıyla, yerine getirilen bir sözü reddetmek veya reddedilen bir sözü yerine getirmek, etkili olmayacaktır.

Bu örnek pasaj, sözün reddedildikten sonra yerine getirilmesine rağmen reddedildiğini göstermektedir.

function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) {
      reject("Cannot divide by 0");
    }

    resolve(numerator / denominator);
  });
}

divide(5,0)
  .then((result) => console.log('result: ', result))
  .catch((error) => console.log('error: ', error));

Öyleyse neden geri dönmemiz gerekiyor?

Yerleşik bir vaat durumunu değiştiremesek de, reddetmek veya çözmek fonksiyonun geri kalanının yürütülmesini durdurmaz. İşlev, kafa karıştırıcı sonuçlar yaratacak bir kod içerebilir. Örneğin:

function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) {
      reject("Cannot divide by 0");
    }
    
    console.log('operation succeeded');

    resolve(numerator / denominator);
  });
}

divide(5, 0)
  .then((result) => console.log('result: ', result))
  .catch((error) => console.log('error: ', error));

İşlev şu anda böyle bir kod içermiyor olsa bile, bu olası bir gelecekteki tuzak oluşturur. Gelecekteki bir refactor, söz verildikten sonra kodun hala yürütüldüğünü görmezden gelebilir ve hata ayıklamak zor olacaktır.

Çözme / reddetme işleminden sonra yürütmeyi durdurma:

Bu standart JS kontrol akışı şeyleridir.

  • Sonra İade resolve/ ' reject:

  • İle Dönüş resolve/ reject- callback'inde dönüş değeri göz ardı edilir, çünkü biz / gidermek ifadeyi reddetmek dönerek bir çizgi kaydedebilirsiniz:

  • Bir if / else bloğu kullanma:

returnKod düz olduğundan seçeneklerden birini kullanmayı tercih ederim .


28
returnBir vaat durumu ayarlandıktan sonra kodun aslında farklı bir şekilde davranmayacağını veya kayda değer olmayacağını belirtmek gerekir, çünkü çağrı resolve()yapıldıktan sonra çağrı reject()yapmak birkaç ekstra CPU döngüsü kullanmak dışında bir şey yapmaz. Ben, kendimi, returnsadece kod temizliği ve verimlilik açısından kullanacağım , ancak bu özel örnekte gerekli değildir.
jfriend00

1
Promise.try(() => { })Yeni Promise yerine kullanmayı deneyin ve çözümleme / reddetme çağrılarını kullanmaktan kaçının. Bunun yerine sadece yazabilirsiniz return denominator === 0 ? throw 'Cannot divide by zero' : numerator / denominator; kullandığım Promise.tryolarak sorunlu try / catch blokları sarılmış sözler ortadan kaldırmak hem de bir Promise kapalı tekme için bir araç olarak.
kingdango

2
Bilmek güzel, ve kalıbı seviyorum. Ancak, şu anda Promise.try bir aşama 0 önerisidir , bu yüzden bunu sadece bir şim ile veya mavi kuş veya Q gibi bir söz kitaplığı kullanarak kullanabilirsiniz
Ori Drori

6
@ jfriend00 Açıkçası bu basit örnekte kod farklı davranmayacaktır. Ama bundan sonra kodunuz olsaydı reject, veritabanlarına veya API uç noktalarına bağlanmak gibi pahalı bir şey yaparsa? Her şey gereksiz olur ve özellikle de bir AWS veritabanı veya API Ağ Geçidi uç noktası gibi bir şeye bağlanıyorsanız, para ve kaynaklara mal olur. Bu durumda gereksiz kodun yürütülmesini önlemek için kesinlikle bir dönüş kullanırsınız.
Jake Wilson

3
@JakeWilson - Tabii ki, bu sadece Javascript'te normal kod akışı ve vaatlerle hiçbir ilgisi yok. İşlevi işlemeyi tamamladıysanız ve geçerli kod yolunda başka kod yürütülmesini istemiyorsanız, bir return.
jfriend00

37

Çay bardağınız olabilir veya olmayabilir, ortak bir deyim, returnile rejectvaadi reddetmek ve işlevden çıkmak için birleştirmektir , böylece işlevi içeren işlevin geri kalanı resolveyürütülmez. Bu stili beğendiyseniz, kodunuzu biraz daha kompakt hale getirebilir.

function divide(numerator, denominator) {
  return new Promise((resolve, reject) => {
    if (denominator === 0) return reject("Cannot divide by 0");
                           ^^^^^^^^^^^^^^
    resolve(numerator / denominator);
  });
}

Promise yapıcı herhangi bir dönüş değeri ile hiçbir şey yapmaz ve her durumda resolveve rejecthiçbir şey döndürmez , çünkü bu iyi çalışır .

Aynı deyim, başka bir cevapta gösterilen geri arama stiliyle kullanılabilir:

function divide(nom, denom, cb){
  if(denom === 0) return cb(Error("Cannot divide by zero"));
                  ^^^^^^^^^
  cb(null, nom / denom);
} 

Yine, bu iyi çalışır çünkü arayan kişi dividehiçbir şey geri dönmesini beklemez ve dönüş değeri ile hiçbir şey yapmaz.


6
Ben bunu sevmiyorum. Bu aslında olmayan bir şeyi iade ettiğiniz fikrini verir. Reddetme işlevini çağırıyorsunuz ve sonra işlev yürütmeyi sonlandırmak için return komutunu kullanıyorsunuz. Onları ayrı satırlarda tutun, yaptığınız şey yalnızca insanları şaşırtacaktır. Kod okunabilirliği kraldır.
K - SO'da toksisite artıyor.

7
@KarlMorrison aslında "bir şey" i iade ediyorsunuz, reddedilmiş bir söz. Bence bahsettiğiniz "nosyon" çok kişisel. rejectStatü döndürmekle ilgili yanlış bir şey yok
Frondor

5
@ Frondor Ne yazdığımı anladığınızı sanmıyorum. Tabii ki sen ve ben bunu anlıyoruz, aynı hatta reddedildiğinde hiçbir şey olmuyor. Peki ya bir projeye giren JavaScript'e alışkın olmayan geliştiriciler? Bu tür programlama, bu tür insanlar için okunabilirliği azaltır. JavaScript eko-sistemi bugün yeterince dağınık ve bu tür uygulamaları yayan insanlar sadece daha da kötüleşecek. Bu kötü bir uygulamadır.
K - SO'da toksisite artıyor.

1
@KarlMorrison Kişisel görüşler! = Kötü uygulama. Muhtemelen yeni bir Javascript geliştiricisinin geri dönüşte neler olduğunu anlamasına yardımcı olacaktır.
Toby Caulk

1
@TobyCaulk İnsanların dönüşün ne yaptığını öğrenmeleri gerekiyorsa, Promises ile oynamamalılar, temel programlamayı öğreniyor olmalılar.
K - SO'da toksisite artıyor.

10

Teknik olarak burada gerekli değildir 1 - çünkü bir Söz sadece ve sadece bir kez çözülebilir veya reddedilebilir . İlk Promise sonucu kazanır ve sonraki her sonuç göz ardı edilir. Bu, Düğüm stili geri aramalardan farklıdır .

Bununla birlikte , pratik olduğunda ve gerçekten de bu durumda daha fazla asenkron / ertelenmiş işlem olmadığı için tam olarak bir kişinin çağrılmasını sağlamak iyi bir temiz uygulamadır . "Erken dönme" kararı , işi tamamlandığında herhangi bir işlevi sonlandırmaktan farklı değildir - ilgisiz veya gereksiz işlemeye devam etmek.

Uygun zamanda geri dönmek (veya "diğer" durumu yürütmekten kaçınmak için koşullu kullanmak) yanlışlıkla kodu geçersiz bir durumda çalıştırma veya istenmeyen yan etkiler yapma olasılığını azaltır; ve böylece kodu 'beklenmedik şekilde kırılmaya' daha az eğilimli hale getirir.


1 Bu teknik cevap ayrıca , bu durumda , "geri dön" den sonraki kodun atlanması durumunda, bir yan etkiye neden olmayacağı gerçeğine de bağlıdır . JavaScript mutlu bir şekilde sıfıra bölünecek ve + Infinity / -Infinity veya NaN döndürecektir.


Güzel dipnot !!
HankCa

9

Bir çözümleme / reddetme işleminden sonra "geri dönmezseniz", durmayı düşündükten sonra kötü şeyler (sayfa yönlendirmesi gibi) olabilir. Kaynak: Buna rastladım.


6
+1 için örnek. Programımın 100'den fazla geçersiz veritabanı sorgusu yapacağı bir sorun yaşadım ve nedenini bulamadım. Bir reddetmeden sonra "geri dönmedim" çıkıyor. Bu küçük bir hata ama dersimi öğrendim.
AdamInTheOculus

8

Ori'nin cevabı zaten gerekli olmadığını açıklıyor, returnancak iyi bir uygulama. Söz vericinin güvenli bir şekilde atıldığını unutmayın, böylece yolda daha sonra geçirilen istisnaları göz ardı eder, aslında kolayca gözlemleyemediğiniz yan etkilere sahip olursunuz.

returnErken aramanın geri aramalarda da çok yaygın olduğunu unutmayın :

function divide(nom, denom, cb){
     if(denom === 0){
         cb(Error("Cannot divide by zero");
         return; // unlike with promises, missing the return here is a mistake
     }
     cb(null, nom / denom); // this will divide by zero. Since it's a callback.
} 

Bu nedenle, vaatlerde iyi bir uygulama olsa da geri aramalarla gereklidir . Kodunuzla ilgili bazı notlar:

  • Kullanım durumunuz varsayımsaldır, aslında senkron eylemlerle vaatler kullanmayın.
  • Promise yapıcısı dönüş değerlerini yok sayar . Bazı kütüphaneler, oraya dönme hatasına karşı sizi uyarmak için tanımlanmamış bir değer döndürürseniz uyarır. Çoğu o kadar akıllı değil.
  • Vaat kurucusu güvenli bir şekilde atıldı, istisnaları reddetmelere dönüştürecek, ancak diğerlerinin işaret ettiği gibi - bir söz bir kez çözülüyor.

4

Birçok durumda parametreleri ayrı ayrı doğrulamak ve Promise.reject (reason) ile derhal reddedilen bir söz vermek mümkündür .

function divide2(numerator, denominator) {
  if (denominator === 0) {
    return Promise.reject("Cannot divide by 0");
  }
  
  return new Promise((resolve, reject) => {
    resolve(numerator / denominator);
  });
}


divide2(4, 0).then((result) => console.log(result), (error) => console.log(error));

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.