Promise.all, Promise.allSettled, Promise.race ve Promise.any, birden fazla Promise'i aynı anda beklemek için kullanılan dört statik yöntemdir. Kısaca: all hepsi başarılı olunca sonuç dizisini verir ve ilk hatada reddeder; allSettled hepsi sonuçlanınca her birinin durumunu raporlar; race ilk sonuçlanan Promise'in sonucunu (başarı ya da hata) alır; any ilk başarılı sonucu alır, hepsi başarısız olursa AggregateError ile reddeder.

Bu yazıda dört yöntemi aynı örnek fonksiyonlarla karşılaştırıyor, boş girdi gibi uç durumları ve sık yapılan hataları gösteriyoruz. Tüm örnekler Node.js 24'te çalıştırıldı. Promise temelleri için Promise nedir yazısına, await sözdizimi için async/await rehberine bakabilirsiniz.

Hızlı karşılaştırma

Hızlı karşılaştırma: Promise.all, Promise.allSettled, Promise.race, Promise.any
YöntemNe zaman fulfilled?Ne zaman rejected?Sonuç
Promise.allHepsi fulfilled oluncaHerhangi biri rejected olunca (ilk hata)Değer dizisi, girdi sırasıyla
Promise.allSettledHepsi sonuçlanıncaHiçbir zaman (girdi Promise'leri için)status/value/reason nesneleri dizisi
Promise.raceİlk sonuçlanan fulfilled iseİlk sonuçlanan rejected iseİlk sonuçlananın değeri veya hatası
Promise.anyHerhangi biri fulfilled oluncaHepsi rejected oluncaİlk değer veya AggregateError

Dördü de bir iterable (genellikle dizi) alır ve yeni bir Promise döndürür. Girdideki Promise olmayan değerler await edilir gibi işlenir; yani 42 gibi bir değer doğrudan sonuca geçer. MDN, bu yöntemlerin JavaScript'in tek iş parçacıklı yapısı içinde "eşzamanlı" çalıştığını, gerçek paralel yürütme sağlamadığını vurgular.

Aşağıdaki tüm örneklerde şu iki yardımcıyı kullanıyoruz:

javascript
const basari = (ms, v) => new Promise((r) => setTimeout(() => r(v), ms));
const hata = (ms, m) => new Promise((_, j) => setTimeout(() => j(new Error(m)), ms));

Promise.all: hepsi ya da hiçbiri

Promise.all, girdi Promise'lerinin hepsi başarılı olduğunda değerleri girdi sırasıyla bir dizi olarak verir; hangisinin önce bittiği önemli değildir. Herhangi biri reddedilirse dönen Promise hemen o ilk hatayla reddedilir.

javascript
(async () => {
  console.log(await Promise.all([basari(200, 'A'), basari(100, 'B'), 42]));
  // [ 'A', 'B', 42 ]

  try {
    await Promise.all([basari(200, 'A'), hata(100, 'B bozuk')]);
  } catch (e) {
    console.log('all:', e.message); // all: B bozuk
  }
})();

Birbirine bağımlı adımlarınız varsa ve biri başarısız olduğunda sonucun anlamı kalmıyorsa all doğru seçimdir. MDN'in örneğinde olduğu gibi, birbirinden bağımsız iki await'i Promise.all ile birleştirmek toplam bekleme süresini en yavaş işleme indirir.

javascript
const is = (id) => new Promise((r) => setTimeout(() => { console.log('bitti', id); r(id); }, 50));

Promise.all([is(1), is(2), Promise.reject(new Error('erken'))])
  .catch((e) => console.log('reddedildi:', e.message));
// reddedildi: erken
// bitti 1
// bitti 2

Promise.allSettled: her sonucu raporla

allSettled hiçbir girdinin hatası yüzünden erken bitmez; hepsi sonuçlanana kadar bekler ve her biri için bir nesne verir. Nesnede status alanı "fulfilled" veya "rejected" olur; başarıda value, hatada reason alanı bulunur.

javascript
(async () => {
  const r = await Promise.allSettled([basari(100, 'A'), hata(50, 'B bozuk'), 99]);
  for (const s of r) {
    console.log(s.status, s.status === 'fulfilled' ? s.value : s.reason.message);
  }
  // fulfilled A
  // rejected B bozuk
  // fulfilled 99

  const basarili = r.filter((s) => s.status === 'fulfilled').map((s) => s.value);
  console.log(basarili); // [ 'A', 99 ]
})();

Birbirinden bağımsız işlemleri (örneğin birkaç servise bildirim göndermek) çalıştırıp hangilerinin başarılı olduğunu görmek istediğinizde uygundur. Sonuç dizisini ayıklarken filter ve map yöntemleri işinizi kolaylaştırır.

Promise.race: ilk sonuçlanan kazanır

race, ilk sonuçlanan Promise'in durumunu aynen alır: ilk biten başarılıysa fulfilled, hatalıysa rejected olur. En yaygın kullanımı bir işleme zaman aşımı eklemektir:

javascript
function zamanAsimi(ms) {
  return new Promise((_, reject) => setTimeout(() => reject(new Error(`${ms} ms aşıldı`)), ms));
}
const yavasIs = new Promise((r) => setTimeout(() => r('veri'), 300));

Promise.race([yavasIs, zamanAsimi(100)])
  .then(console.log)
  .catch((e) => console.log(e.message)); // 100 ms aşıldı

Burada da kaybeden işlem iptal edilmez; yavasIs arka planda bitmeye devam eder. MDN ayrıca uzun süre bekleyen aynı Promise'i tekrar tekrar race'e vermenin, o Promise üzerinde işleyicilerin birikmesine yol açabileceği konusunda uyarır.

Promise.any ve AggregateError

any, reddedilen Promise'leri ilk başarılı sonuç gelene kadar yok sayar. Bu yüzden önce bir hata gelse bile sonraki başarılı sonucu alırsınız. Hepsi reddedilirse dönen Promise bir AggregateError ile reddedilir; tek tek hatalar bu nesnenin errors dizisinde, girdi sırasıyla durur.

javascript
(async () => {
  console.log(await Promise.any([hata(50, 'x'), basari(200, 'yavaş'), basari(100, 'hızlı')]));
  // hızlı

  try {
    await Promise.any([hata(50, 'birinci'), hata(100, 'ikinci')]);
  } catch (e) {
    console.log(e instanceof AggregateError, e.name); // true AggregateError
    console.log(e.message); // All promises were rejected
    console.log(e.errors.map((x) => x.message)); // [ 'birinci', 'ikinci' ]
  }
})();

message metni motora göre değişir; yukarıdaki Node.js 24 çıktısıdır. Kendi kodunuzda birden fazla bağımsız hatayı raporlamak için new AggregateError(hatalar, mesaj) ile bu sınıfı doğrudan da oluşturabilirsiniz. Hata türlerinin geneli için hata yönetimi yazımıza bakın.

MDN, any ile all arasındaki ilişkiyi dizilerdeki some() ve every() ilişkisine benzetir. Aynı içeriği birkaç yedek kaynaktan isteyip ilk yanıt vereni kullanmak tipik bir any senaryosudur.

Uç durumlar: boş dizi ve senkronluk

Uç durumlar: boş dizi ve senkronluk: Promise.all, Promise.allSettled, Promise.any, Promise.race

Boş bir iterable verdiğinizde dört yöntem farklı davranır. Ayrıca boş olmayan girdi zaten sonuçlanmış Promise'lerden oluşsa bile sonuç her zaman asenkron olarak belirlenir.

javascript
const p1 = Promise.all([]);
const p2 = Promise.allSettled([]);
const p3 = Promise.any([]);
p3.catch(() => {});
const p4 = Promise.race([]);
console.log(p1); // Promise { [] }
console.log(p2); // Promise { [] }
console.log(p4); // Promise { <pending> }
YöntemBoş iterable verilirse
Promise.allHemen boş diziyle fulfilled
Promise.allSettledHemen boş diziyle fulfilled
Promise.anyHemen AggregateError ile rejected
Promise.raceSonsuza kadar pending kalır

await ile kullanım ve sıralı alternatif

Bu yöntemler bir Promise döndürdüğü için await ile doğal biçimde birleşir. Sonuç sayısı belli olduğunda dizi destructuring ile her sonucu ayrı bir değişkene alabilirsiniz. Sonuç sırası girdi sırasıyla aynıdır; ilk işlemin daha geç bitmesi bu sırayı değiştirmez.

Bazen işlemlerin gerçekten sırayla çalışması gerekir, çünkü her adım bir öncekinin sonucuna ihtiyaç duyar. MDN, bunun için Promise döndüren fonksiyonlardan oluşan bir diziyi reduce ile tek bir zincire dönüştürmeyi gösterir. Aynı işi for...of içinde await ile de yapabilirsiniz. Ancak MDN'in hatırlattığı gibi, adımlar birbirine bağlı değilse işlemleri eşzamanlı çalıştırmak her zaman daha iyidir.

javascript
const bekle = (ms, deger) => new Promise((r) => setTimeout(() => r(deger), ms));

(async () => {
  const [kullanici, ayarlar] = await Promise.all([bekle(50, 'Deniz'), bekle(20, { tema: 'koyu' })]);
  console.log(kullanici, ayarlar.tema); // Deniz koyu
})();

const adimlar = [
  (x) => bekle(30, x + 1),
  (x) => bekle(30, x * 10),
  (x) => bekle(30, x - 5),
];
adimlar
  .reduce((p, f) => p.then(f), Promise.resolve(1))
  .then((sonuc) => console.log('reduce:', sonuc)); // reduce: 15

Dördü de girdi Promise'lerini çağrıldıkları anda "işlenmiş" olarak işaretler. MDN'e göre bu nedenle ilk sonuçtan sonra gelen retler unhandledrejection olayını tetiklemez; yani kaybeden işlemlerin hataları sessizce yok sayılır. Bu hataları da kaydetmek istiyorsanız allSettled daha uygun olabilir.

Hangi yöntemi seçmeli?

Hangi yöntemi seçmeli? Tüm sonuçlara ihtiyacınız var ve biri bile başarısızsa işlem..., Her işlemin sonucunu ayrı ayrı görmek istiyorsanız, Zaman aşımı veya "ilk biten" mantığı...
  • Tüm sonuçlara ihtiyacınız var ve biri bile başarısızsa işlem anlamsızsa: Promise.all.
  • Her işlemin sonucunu ayrı ayrı görmek istiyorsanız: Promise.allSettled.
  • Zaman aşımı veya "ilk biten" mantığı gerekiyorsa: Promise.race.
  • Birkaç yedek kaynaktan ilk başarılı yanıt yeterliyse: Promise.any.

Sık yapılan hatalar

Promise yerine fonksiyon vermek

Bu yöntemler Promise bekler. Async fonksiyonun kendisini verirseniz çağrılmaz ve sonuç olarak fonksiyonun kendisini geri alırsınız:

javascript
const f = async () => 1;
(async () => {
  const yanlis = await Promise.all([f, f]);
  console.log(typeof yanlis[0]); // function
  const dogru = await Promise.all([f(), f()]);
  console.log(dogru); // [ 1, 1 ]
})();

Sonuç dizisinin sırasını karıştırmak

all ve allSettled sonuçları tamamlanma sırasına göre değil, girdi sırasına göre verir. Destructuring yaparken değişken sırasının girdi sırasıyla aynı olduğundan emin olun.

Reddin işlemleri durduracağını sanmak

Hiçbir birleştirici, kaybeden veya kalan işlemleri iptal etmez. Yan etkileri olan işlemlerde bunu hesaba katın.

Sık Sorulan Sorular

Promise.all işlemleri paralel mi çalıştırır?

İşlemler Promise.all çağrılmadan önce, Promise'leri oluşturduğunuz anda başlar. all yalnızca hepsini birlikte bekler. JavaScript tek iş parçacığında çalıştığı için bu bir eşzamanlılıktır; gerçek paralellik için worker gerekir.

allSettled reddedilebilir mi?

Girdi Promise'lerinin hatası yüzünden reddedilmez. Her hata, sonuç dizisinde status: "rejected" olan bir nesneye dönüşür.

race ile any arasındaki fark nedir?

race ilk sonuçlanan Promise'e bakar ve o bir hataysa reddeder. any ilk başarılı Promise'e bakar; hataları, hepsi başarısız olmadıkça yok sayar.

AggregateError içindeki hatalara nasıl ulaşırım?

errors özelliği, toplanan hataların dizisidir. Promise.any için bu dizi, girdi sırasına göre her Promise'in ret sebebini içerir.

Girdide Promise olmayan değerler olursa ne olur?

Sorun olmaz. MDN'e göre bu değerler await edilir gibi işlenir: thenable olanlar çözülür, diğerleri olduğu gibi sonuca geçer. Promise.all([1, 2, 3]) bu yüzden [1, 2, 3] ile fulfilled olur, ama yine de asenkron olarak.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: JavaScript öğrenme rehberi · Promise nedir · async/await · Hata yönetimi · Event loop · Node.js REST API