Benjamin'in cevabı bu sorunu çözmek için harika bir soyutlama sunuyor, ancak daha az soyut bir çözüm umuyordum. Bu sorunu çözmenin açık yolu, yalnızca .catch
iç vaatleri çağırmak ve hatayı geri aramalarından döndürmektir.
let a = new Promise((res, rej) => res('Resolved!')),
b = new Promise((res, rej) => rej('Rejected!')),
c = a.catch(e => { console.log('"a" failed.'); return e; }),
d = b.catch(e => { console.log('"b" failed.'); return e; });
Promise.all([c, d])
.then(result => console.log('Then', result)) // Then ["Resolved!", "Rejected!"]
.catch(err => console.log('Catch', err));
Promise.all([a.catch(e => e), b.catch(e => e)])
.then(result => console.log('Then', result)) // Then ["Resolved!", "Rejected!"]
.catch(err => console.log('Catch', err));
Bu bir adım daha ileri giderek, şöyle görünen genel bir catch işleyici yazabilirsiniz:
const catchHandler = error => ({ payload: error, resolved: false });
o zaman yapabilirsin
> Promise.all([a, b].map(promise => promise.catch(catchHandler))
.then(results => console.log(results))
.catch(() => console.log('Promise.all failed'))
< [ 'Resolved!', { payload: Promise, resolved: false } ]
Buradaki sorun, yakalanan değerlerin yakalanmayan değerlerden farklı bir arayüze sahip olmasıdır, bu nedenle bunu temizlemek için şöyle bir şey yapabilirsiniz:
const successHandler = result => ({ payload: result, resolved: true });
Şimdi bunu yapabilirsiniz:
> Promise.all([a, b].map(result => result.then(successHandler).catch(catchHandler))
.then(results => console.log(results.filter(result => result.resolved))
.catch(() => console.log('Promise.all failed'))
< [ 'Resolved!' ]
Daha sonra KURU tutmak için Benjamin'in cevabına ulaşırsınız:
const reflect = promise => promise
.then(successHandler)
.catch(catchHander)
şimdi nereye benziyor
> Promise.all([a, b].map(result => result.then(successHandler).catch(catchHandler))
.then(results => console.log(results.filter(result => result.resolved))
.catch(() => console.log('Promise.all failed'))
< [ 'Resolved!' ]
İkinci çözümün faydaları, soyutlanmış ve KURU olmasıdır. Dezavantajı, daha fazla kodunuz olması ve şeyleri tutarlı hale getirmek için tüm vaatlerinizi yansıtmayı hatırlamanız gerekir.
Çözümümü açık ve KISS olarak nitelendirebilirdim, ama gerçekten daha az sağlam. Arayüz, sözün başarılı olup olmadığını tam olarak bildiğinizi garanti etmez.
Örneğin, aşağıdakilere sahip olabilirsiniz:
const a = Promise.resolve(new Error('Not beaking, just bad'));
const b = Promise.reject(new Error('This actually didnt work'));
Bu yakalanmayacak a.catch
, bu yüzden
> Promise.all([a, b].map(promise => promise.catch(e => e))
.then(results => console.log(results))
< [ Error, Error ]
Hangisinin ölümcül hangisinin ölümcül olmadığını anlamanın bir yolu yoktur. Eğer bu önemliyse, başarılı olup olmadığını takip eden bir uygulama yapmak ve arayüz kurmak isteyeceksiniz reflect
.
Hataları sadece incelikle işlemek istiyorsanız, hataları tanımsız değerler olarak ele alabilirsiniz:
> Promise.all([a.catch(() => undefined), b.catch(() => undefined)])
.then((results) => console.log('Known values: ', results.filter(x => typeof x !== 'undefined')))
< [ 'Resolved!' ]
Benim durumumda, hatayı veya nasıl başarısız olduğunu bilmeme gerek yok - sadece değere sahip olup olmadığımı umursuyorum. Sözünü veren işlevin, belirli bir hatayı günlüğe kaydetme konusunda endişelenmesine izin vereceğim.
const apiMethod = () => fetch()
.catch(error => {
console.log(error.message);
throw error;
});
Bu şekilde, uygulamanın geri kalanı isterse hatasını yok sayabilir ve isterse tanımsız bir değer olarak değerlendirebilir.
Üst düzey işlevlerimin güvenli bir şekilde başarısız olmasını ve bağımlılıklarının neden başarısız olduğuna dair ayrıntılar hakkında endişelenmemesini istiyorum ve bu ödünleşimi yapmak zorunda kaldığımda da KISS'i KURU tercih ediyorum - sonuçta kullanmamayı seçtim reflect
.