Bazıları reddedilse bile tüm vaatlerin tamamlanmasını bekleyin


405

Diyelim Promiseki bir tane başarısız olacak ağ istekleri yapan s bir dizi var :

// http://does-not-exist will throw a TypeError
var arr = [ fetch('index.html'), fetch('http://does-not-exist') ]

Promise.all(arr)
  .then(res => console.log('success', res))
  .catch(err => console.log('error', err)) // This is executed   

Diyelim ki başarısız olursa olsun, tüm bunlar bitene kadar beklemek istiyorum. Onsuz yaşayabileceğim bir kaynak için bir ağ hatası olabilir, ancak alabilirsem ilerlemeden önce istiyorum. Ağ hatalarını zarif bir şekilde ele almak istiyorum.

Bunun Promises.alliçin yer bırakmadığından, bir vaat kütüphanesi kullanmadan bunu işlemek için önerilen model nedir?


Reddedilen vaatler için sonuç dizisinde ne döndürülmelidir?
Kuba Wyrostek

9
ES6, böyle bir yöntemi desteklemeyeceğini vaat ediyor (ve şu anda Bluebird'den daha yavaş görünüyor ). Ayrıca, tüm tarayıcılar veya motorlar henüz onları desteklememektedir. Ben ediyorum şiddetle birlikte gelen Bluebird, kullanmanızı tavsiye allSettledKendi rulo zorunda kalmadan hangi tatmin ihtiyacını.
Dan Pantry

@KubaWyrostek Promise.all'ın mantıklı olduğunu düşündüğüm bu davranışa sahip olmamasının nedenini ortaya koyduğunuzu düşünüyorum. Bu şekilde çalışmaz, ancak alternatif bir görüş Promise.all'ın asla başarısız olmayan özel bir söz vermesi gerektiğini ve başarısız vaatleri temsil eden argüman olarak atılan hatayı alacağını söylemek olacaktır.
Nathan Hagen

Dan'ın paylaştıklarına eklemek için, mavi kuşun sahip olduğu allSettled / settleAll benzeri işlevsellik "yansıtma" işlevi aracılığıyla kullanılabilir.
user3344977

2
@Coli: Hmm, sanmıyorum. herhangi bir söz Promise.allreddedilir reddedilmez , bu nedenle önerilen deyim tüm sözlerin yerine getirileceğini garanti etmez.
Jörg W Mittag

Yanıtlar:


309

Güncelleme, muhtemelen yerleşik yerel kullanmak istiyorsunuz Promise.allSettled:

Promise.allSettled([promise]).then(([result]) => {
   //reach here regardless
   // {status: "fulfilled", value: 33}
});

Eğlenceli bir gerçek olarak, aşağıdaki bu cevap, bu yöntemi dile eklerken önceki teknikti:]


Elbette, sadece şunlara ihtiyacınız var reflect:

const reflect = p => p.then(v => ({v, status: "fulfilled" }),
                            e => ({e, status: "rejected" }));

reflect(promise).then((v => {
    console.log(v.status);
});

Veya ES5 ile:

function reflect(promise){
    return promise.then(function(v){ return {v:v, status: "fulfilled" }},
                        function(e){ return {e:e, status: "rejected" }});
}


reflect(promise).then(function(v){
    console.log(v.status);
});

Veya örneğinizde:

var arr = [ fetch('index.html'), fetch('http://does-not-exist') ]

Promise.all(arr.map(reflect)).then(function(results){
    var success = results.filter(x => x.status === "fulfilled");
});

3
Bence bu harika bir çözüm. Daha basit bir sözdizimi içerecek şekilde değiştirebilir misiniz? Sorunun temel noktası, alt vaatlerdeki hataları ele almak istiyorsanız, onları yakalamanız ve hatayı döndürmeniz gerektiğidir. Örneğin: gist.github.com/nhagen/a1d36b39977822c224b8
Nathan Hagen

3
@NathanHagen, neyin reddedildiğini ve neyin yerine getirildiğini anlamanıza ve sorunu yeniden kullanılabilir bir operatöre çıkarmanıza izin verir.
Benjamin Gruenbaum

4
Kendi sorunuma yanıt olarak şu npm paketini oluşturdum: github.com/Bucabug/promise-reflect npmjs.com/package/promise-reflect
SamF

2
Bir süre önce bu sorunla karşılaştım ve bunun için bu npm paketini oluşturdum: npmjs.com/package/promise-all-soft-fail
velocity_distance

5
Kelime mi reflectbilgisayar biliminde yaygın bir kelime? Lütfen bunun wikipedia'da olduğu gibi açıklandığı yere bağlantı verebilir misiniz? Çok aradım Promise.all not even first rejectama "Yansıt" kelimesini aramayı bilmiyordum. ES6'da Promise.reflect"Promise.all ama gerçekten hepsi" gibi bir şey olmalı mı ?
Noitidart

253

Benzer cevap, ancak ES6 için daha deyimsel:

const a = Promise.resolve(1);
const b = Promise.reject(new Error(2));
const c = Promise.resolve(3);

Promise.all([a, b, c].map(p => p.catch(e => e)))
  .then(results => console.log(results)) // 1,Error: 2,3
  .catch(e => console.log(e));


const console = { log: msg => div.innerHTML += msg + "<br>"};
<div id="div"></div>

Değerlerin türüne bağlı olarak (ler) hataları genellikle kolayca yeterince ayırt edilebilir, iade (örn kullanımı undefined, "umurumda değil" için typeofdüz olmayan nesne değerleri için, result.message, result.toString().startsWith("Error:")vs.)


1
@KarlBateman Sanırım kafan karıştı. .map(p => p.catch(e => e))Parça fonksiyonları tüm reddetmeleri çözülmüş değerlere dönüştürdüğünden, sipariş fonksiyonları çözülür veya reddedilir Promise.all. Dene.
jib

39
.catch(e => console.log(e));asla çağrılmaz çünkü bu asla başarısız olmaz
fregante

4
@ bfred.it Doğru. Söz zincirlerini sonlandırmak catchgenelde iyi bir uygulamadır IMHO .
jib

2
@SuhailGupta Hatayı yakalar eve normal (başarılı) bir değer olarak döndürür. p.catch(function(e) { return e; })Sadece daha kısa olanla aynı . returnörtük.
jib

1
@ JustinReusnow zaten yorumlarda yer aldı. Daha sonra kod eklemeniz durumunda zincirleri sonlandırmak için her zaman iyi bir uygulama.
jib

71

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 .catchiç 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.


1
@ Benjamin Sanırım @ Nathan'ın çözümü Promises için çok basit ve deyimsel . Senin ederken reflectkodu yeniden geliştirir, aynı zamanda soyutlama başka seviyesini belirler. Nathan'ın yanıtı şimdiye kadar sadece sizinkine kıyasla bir miktar upvotes aldığından, bunun henüz tanımadığım çözümüyle ilgili bir sorunun göstergesi olup olmadığını merak ediyorum.

2
@ LUH3417 bu çözüm kavramsal olarak daha az sestir, çünkü hataları değerler olarak ele alır ve hataları hatalardan ayırmaz. Örneğin, vaatlerden biri meşru bir şekilde atılabilecek bir değere (tamamen mümkündür) karar verirse, bu oldukça kötü bir şekilde kırılır.
Benjamin Gruenbaum

2
@BenjaminGruenbaum Mesela, new Promise((res, rej) => res(new Error('Legitimate error'))ayırt edilemez new Promise(((res, rej) => rej(new Error('Illegitimate error'))mi? Ya da daha fazlasına göre filtreleyemez x.statusmisiniz? Cevabımı bu noktaya ekleyeceğim, böylece fark daha net
Nathan Hagen

3
Bunun kötü bir fikir olmasının nedeni, Promise uygulamasını yalnızca belirli bir Promise.all()varyasyonda kullanılmakta olan belirli bir kullanım durumuna bağlamasıdır, daha sonra belirli bir sözün reddedemeyeceğini, ancak reddedeceğini bilmek için Promise tüketicisinde görev alır. hatalarını yut. Aslında reflect()yöntem daha az 'soyut' ve daha açık hale getirilebilir PromiseEvery(promises).then(...), yukarıdaki cevabın Benjamin'inkine kıyasla karmaşıklığı bu çözüm hakkında çok şey söylemelidir.
Neil

33

Var bitmiş önerisi vanilya JavaScript, doğal olarak bunu yapabilecek bir işlev için: Promise.allSettled4. aşamadan bunu yaptı, ES2020 içinde, resmileştirilmiş edilir ve uygulanan tüm modern ortamlar . Bu diğer cevaptakireflect işleve çok benzer . İşte teklif sayfasından bir örnek. Daha önce yapmanız gerekecekti:

function reflect(promise) {
  return promise.then(
    (v) => {
      return { status: 'fulfilled', value: v };
    },
    (error) => {
      return { status: 'rejected', reason: error };
    }
  );
}

const promises = [ fetch('index.html'), fetch('https://does-not-exist/') ];
const results = await Promise.all(promises.map(reflect));
const successfulPromises = results.filter(p => p.status === 'fulfilled');

Kullanılması Promise.allSettledyerine yukarıdaki eşdeğer olacaktır:

const promises = [ fetch('index.html'), fetch('https://does-not-exist/') ];
const results = await Promise.allSettled(promises);
const successfulPromises = results.filter(p => p.status === 'fulfilled');

Modern ortamları kullananlar bu yöntemi herhangi bir kütüphane olmadan kullanabilirler . Bunlarda, aşağıdaki snippet sorunsuz çalışmalıdır:

Promise.allSettled([
  Promise.resolve('a'),
  Promise.reject('b')
])
  .then(console.log);

Çıktı:

[
  {
    "status": "fulfilled",
    "value": "a"
  },
  {
    "status": "rejected",
    "reason": "b"
  }
]

Eski tarayıcılar için, bir spec uyumlu polyfill orada burada .


1
Aşama 4 ve ES2020'ye inmesi gerekiyor.
Estus Flask

Ayrıca Düğüm 12'de mevcuttur :)
Callum M

Diğer cevaplar hala geçerli olsa bile, bu sorunu çözmenin en güncel yolu olduğu için bu daha fazla oy almalıdır.
Jacob

9

Benjamin'in cevabını gerçekten seviyorum ve tüm vaatleri nasıl her zaman sonuç olarak her zaman çözen ama bazen de hata ile çözenlere dönüştürüyor. :)
Alternatif arayışında olmanız durumunda isteğiniz doğrultusunda çalışacağım. Bu yöntem, hataları geçerli sonuçlar olarak ele alır ve Promise.allaksi takdirde benzer şekilde kodlanır :

Promise.settle = function(promises) {
  var results = [];
  var done = promises.length;

  return new Promise(function(resolve) {
    function tryResolve(i, v) {
      results[i] = v;
      done = done - 1;
      if (done == 0)
        resolve(results);
    }

    for (var i=0; i<promises.length; i++)
      promises[i].then(tryResolve.bind(null, i), tryResolve.bind(null, i));
    if (done == 0)
      resolve(results);
  });
}

Buna genellikle denir settle. Biz de mavi kuş var, ben daha iyi yansıtmak istiyorum ama bu bir dizi için bu olduğunda uygun bir çözümdür.
Benjamin Gruenbaum

2
Tamam, yerleşmek gerçekten daha iyi bir isim olacak. :)
Kuba Wyrostek

Bu açık söz inşaat antipatternine çok benziyor. Böyle bir işlevi asla kendiniz yazmamalısınız, ancak kütüphanenizin sağladığı işlevi kullanın (Tamam, yerel ES6 biraz yetersizdir).
Bergi

Lütfen yapıcıyı Promisedoğru bir şekilde kullanabilir misiniz (ve o var resolveşeyden kaçınabilir misiniz?)
Bergi

Bergi, cevabı istediğin gibi değiştirmekten çekinmeyin.
Kuba Wyrostek

5
var err;
Promise.all([
    promiseOne().catch(function(error) { err = error;}),
    promiseTwo().catch(function(error) { err = error;})
]).then(function() {
    if (err) {
        throw err;
    }
});

Promise.allReddedilen sözünü yutmak ve vaatler tüm çözmüş zaman dönecektir böylece, bir değişkene hatayı saklayacaktır. Ardından hatayı yeniden atabilir veya her şeyi yapabilirsiniz. Bu şekilde, sanırım birincisi yerine son reddi elde edersiniz.


1
Bu bir dizi yaparak ve kullanarak errs toplayabilir gibi görünüyor err.push(error), böylece tüm hatalar kabarmış olabilir.
ps2goat

4

Aynı sorunu yaşadım ve şu şekilde çözdüm:

const fetch = (url) => {
  return node-fetch(url)
    .then(result => result.json())
    .catch((e) => {
      return new Promise((resolve) => setTimeout(() => resolve(fetch(url)), timeout));
    });
};

tasks = [fetch(url1), fetch(url2) ....];

Promise.all(tasks).then(......)

Bu durumda Promise.allher Sözün gelmesini resolvedveya rejecteddevletin gelmesini bekleyecektir .

Ve bu çözüme sahip olursak, catchengellenmeyen bir şekilde "uygulamayı durduruyoruz ". Aslında, hiçbir şeyi durdurmuyoruz, sadece zaman aşımından sonra çözüldüğünde Promisebaşka bir döndüren bekleyen bir duruma geri dönüyoruz Promise.


Ancak bu, koştuğunuzda tüm vaatleri çağırır Promise.all. Tüm vaatler çağrıldığında dinlemenin bir yolunu arıyorum ama onları kendim çağırmıyorum. Teşekkürler.
SudoPlz

@SudoPlz yöntem all()bunu yapar, tüm Vaatlerin yerine getirilmesini veya en az birini reddetmeyi bekler.
user1016265

bu doğru, ama sadece beklemek değil, aslında süreci başlatır / başlatır / başlatır. Eğer vaatleri mümkün olmayacak başka bir yerde kovmak istersen, .allherşeyi tetikler .
SudoPlz

@SudoPlz bu fikrinizi değiştireceğini umuyoruz jsfiddle.net/d1z1vey5
user1016265

3
Ben düzeltilmiş duruyorum. Şimdiye kadar Promises'ın sadece biri onları çağırdığında (aka a thenveya .allçağrı olarak) çalıştığını, ancak oluşturulduğunda çalıştığını düşündüm .
SudoPlz

2

Bu, Q'nun nasıl yaptığı ile tutarlı olmalıdır :

if(!Promise.allSettled) {
    Promise.allSettled = function (promises) {
        return Promise.all(promises.map(p => Promise.resolve(p).then(v => ({
            state: 'fulfilled',
            value: v,
        }), r => ({
            state: 'rejected',
            reason: r,
        }))));
    };
}

2

Benjamin Gruenbaum'un cevabı elbette harika. Ama aynı zamanda Nathan Hagen'in soyutlama seviyesinin belirsiz göründüğünü de görebiliyorum. Gibi kısa nesne özelliklerine sahip olmake & v olmak da yardımcı olmaz, ancak elbette bu değiştirilebilir.

JavaScript adlandırılan standart hata nesnesi yok Error. İdeal olarak her zaman bunun bir örneğini / torununu atarsınız. Avantajı yapabileceğiniz instanceof Errorve bir şeyin bir hata olduğunu bilmenizdir.

Bu fikri kullanarak, burada benim sorunum var.

Temel olarak hatayı yakalayın, hata Hata türü değilse, hatayı bir Error nesnesinin içine sarın. Sonuçta elde edilen dizi ya çözümlenmiş değerlere ya da kontrol edebileceğiniz Hata nesnelerine sahip olacaktır.

Yakalamanın içindeki örnek reject("error"), bunun yerine belki de bazı harici kütüphaneleri kullanmanız durumundadır reject(new Error("error")).

Tabii ki bir hatayı çözeceğinize dair vaatleriniz olabilir, ancak bu durumda son örnekte olduğu gibi yine de bir hata gibi davranmanız mantıklı olacaktır.

Bunu yapmanın bir başka avantajı, dizi yıkımının basit tutulmasıdır.

const [value1, value2] = PromiseAllCatch(promises);
if (!(value1 instanceof Error)) console.log(value1);

Onun yerine

const [{v: value1, e: error1}, {v: value2, e: error2}] = Promise.all(reflect..
if (!error1) { console.log(value1); }

!error1Çekin bir örnekten daha basit olduğunu, ancak her ikisini de yıkmanız gerektiğini iddia edebilirsiniz v & e.

function PromiseAllCatch(promises) {
  return Promise.all(promises.map(async m => {
    try {
      return await m;
    } catch(e) {
      if (e instanceof Error) return e;
      return new Error(e);
    }
  }));
}


async function test() {
  const ret = await PromiseAllCatch([
    (async () => "this is fine")(),
    (async () => {throw new Error("oops")})(),
    (async () => "this is ok")(),
    (async () => {throw "Still an error";})(),
    (async () => new Error("resolved Error"))(),
  ]);
  console.log(ret);
  console.log(ret.map(r =>
    r instanceof Error ? "error" : "ok"
    ).join(" : ")); 
}

test();


2

Reddetmek yerine bir nesneyle çözün. Söz verirken böyle bir şey yapabilirsiniz

const promise = arg => {
  return new Promise((resolve, reject) => {
      setTimeout(() => {
        try{
          if(arg != 2)
            return resolve({success: true, data: arg});
          else
            throw new Error(arg)
        }catch(e){
          return resolve({success: false, error: e, data: arg})
        }
      }, 1000);
  })
}

Promise.all([1,2,3,4,5].map(e => promise(e))).then(d => console.log(d))


1
Bu güzel değil, zarif değil ama işe yarayacak görünüyor
Sunny Tambi

1

Ben ... Aşağıdaki teklifler biraz daha farklı bir yaklaşım düşünüyorum karşılaştırmak fn_fast_fail()ile fn_slow_fail()... ikincisi gibi başarısız değildir gerçi ... Eğer biri veya her ikisi olmadığını kontrol edebilir ave bbir örneğidir Errorve throwbu Errorsize ulaşmak için isterseniz catchblok (örneğin if (b instanceof Error) { throw b; }). Bkz. Jsfiddle .

var p1 = new Promise((resolve, reject) => { 
    setTimeout(() => resolve('p1_delayed_resolvement'), 2000); 
}); 

var p2 = new Promise((resolve, reject) => {
    reject(new Error('p2_immediate_rejection'));
});

var fn_fast_fail = async function () {
    try {
        var [a, b] = await Promise.all([p1, p2]);
        console.log(a); // "p1_delayed_resolvement"
        console.log(b); // "Error: p2_immediate_rejection"
    } catch (err) {
        console.log('ERROR:', err);
    }
}

var fn_slow_fail = async function () {
    try {
        var [a, b] = await Promise.all([
            p1.catch(error => { return error }),
            p2.catch(error => { return error })
        ]);
        console.log(a); // "p1_delayed_resolvement"
        console.log(b); // "Error: p2_immediate_rejection"
    } catch (err) {
        // we don't reach here unless you throw the error from the `try` block
        console.log('ERROR:', err);
    }
}

fn_fast_fail(); // fails immediately
fn_slow_fail(); // waits for delayed promise to resolve

0

İşte benim gelenekim settledPromiseAll()

const settledPromiseAll = function(promisesArray) {
  var savedError;

  const saveFirstError = function(error) {
    if (!savedError) savedError = error;
  };
  const handleErrors = function(value) {
    return Promise.resolve(value).catch(saveFirstError);
  };
  const allSettled = Promise.all(promisesArray.map(handleErrors));

  return allSettled.then(function(resolvedPromises) {
    if (savedError) throw savedError;
    return resolvedPromises;
  });
};

Nazaran Promise.all

  • Tüm vaatler çözülürse, tam olarak standart olanı yerine getirir.

  • Daha fazla vaatten biri reddedilirse, birincisi standart olanla aynı şekilde reddedilir, ancak aksine tüm vaatlerin çözülmesini / reddedilmesini bekler.

Cesur için değiştirebiliriz Promise.all():

(function() {
  var stdAll = Promise.all;

  Promise.all = function(values, wait) {
    if(!wait)
      return stdAll.call(Promise, values);

    return settledPromiseAll(values);
  }
})();

DİKKATLİ . Genel olarak, hiçbir zaman ilgili olmayan JS kitaplıklarını kırabileceği veya JS standartlarında gelecekteki değişikliklerle çakışabileceğinden yerleşikleri değiştirmeyiz.

My settledPromiseallile geriye dönük uyumludur Promise.allve işlevselliğini arttırır.

Standartlar geliştiren insanlar - bunu neden yeni bir Promise standardına dahil etmiyorsunuz?


0

Promise.allmodern async/awaityaklaşım kullanarak

const promise1 = //...
const promise2 = //...

const data = await Promise.all([promise1, promise2])

const dataFromPromise1 = data[0]
const dataFromPromise2 = data[1]

-1

Yapardım:

var err = [fetch('index.html').then((success) => { return Promise.resolve(success); }).catch((e) => { return Promise.resolve(e); }),
fetch('http://does-not-exist').then((success) => { return Promise.resolve(success); }).catch((e) => { return Promise.resolve(e); })];

Promise.all(err)
.then(function (res) { console.log('success', res) })
.catch(function (err) { console.log('error', err) }) //never executed

-1

Eşzamanlı olarak eşzamanlı yürütücü nsynjs aracılığıyla mantığınızı çalıştırabilirsiniz . Her bir vaadi duraklatır, çözüm / ret bekler ve çözümün sonucunu datamülke atar veya bir istisna atar (denemek / yakalama bloğuna ihtiyacınız olacak işlem için). İşte bir örnek:

function synchronousCode() {
    function myFetch(url) {
        try {
            return window.fetch(url).data;
        }
        catch (e) {
            return {status: 'failed:'+e};
        };
    };
    var arr=[
        myFetch("https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"),
        myFetch("https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/NONEXISTANT.js"),
        myFetch("https://ajax.NONEXISTANT123.com/ajax/libs/jquery/2.0.0/NONEXISTANT.js")
    ];
    
    console.log('array is ready:',arr[0].status,arr[1].status,arr[2].status);
};

nsynjs.run(synchronousCode,{},function(){
    console.log('done');
});
<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>


-1

ES5'ten beri aşağıdaki kodları kullanıyorum.

Promise.wait = function(promiseQueue){
    if( !Array.isArray(promiseQueue) ){
        return Promise.reject('Given parameter is not an array!');
    }

    if( promiseQueue.length === 0 ){
        return Promise.resolve([]);
    }

    return new Promise((resolve, reject) =>{
        let _pQueue=[], _rQueue=[], _readyCount=false;
        promiseQueue.forEach((_promise, idx) =>{
            // Create a status info object
            _rQueue.push({rejected:false, seq:idx, result:null});
            _pQueue.push(Promise.resolve(_promise));
        });

        _pQueue.forEach((_promise, idx)=>{
            let item = _rQueue[idx];
            _promise.then(
                (result)=>{
                    item.resolved = true;
                    item.result = result;
                },
                (error)=>{
                    item.resolved = false;
                    item.result = error;
                }
            ).then(()=>{
                _readyCount++;

                if ( _rQueue.length === _readyCount ) {
                    let result = true;
                    _rQueue.forEach((item)=>{result=result&&item.resolved;});
                    (result?resolve:reject)(_rQueue);
                }
            });
        });
    });
};

Kullanım imzası gibidir Promise.all. En büyük fark, Promise.waittüm vaatlerin işlerini bitirmesini bekleyecek olmasıdır.


-1

Bu sorunun çok fazla cevabı olduğunu biliyorum ve eminim (hepsi değilse de) doğru olmalı. Ancak bu cevapların mantığını / akışını anlamak benim için çok zordu.

Bu yüzden Orijinal Uygulamaya baktım ve Promise.all()bir Sözün başarısız olması durumunda yürütmeyi durdurmama haricinde bu mantığı taklit etmeye çalıştım.

  public promiseExecuteAll(promisesList: Promise<any>[] = []): Promise<{ data: any, isSuccess: boolean }[]>
  {
    let promise: Promise<{ data: any, isSuccess: boolean }[]>;

    if (promisesList.length)
    {
      const result: { data: any, isSuccess: boolean }[] = [];
      let count: number = 0;

      promise = new Promise<{ data: any, isSuccess: boolean }[]>((resolve, reject) =>
      {
        promisesList.forEach((currentPromise: Promise<any>, index: number) =>
        {
          currentPromise.then(
            (data) => // Success
            {
              result[index] = { data, isSuccess: true };
              if (promisesList.length <= ++count) { resolve(result); }
            },
            (data) => // Error
            {
              result[index] = { data, isSuccess: false };
              if (promisesList.length <= ++count) { resolve(result); }
            });
        });
      });
    }
    else
    {
      promise = Promise.resolve([]);
    }

    return promise;
  }

Açıklama:
- Girdi üzerinde döngü yapın promisesListve her bir Sözü yerine getirin.
- Söz çözülmesi veya reddedilir olursa olsun: Promise'in sonucu bir kurtarış içinde resultdiziye göre index. Çöz / reddet durumunu da kaydet (isSuccess ).
- Tüm Sözler tamamlandığında, diğerlerinin sonucu ile bir Söz iade edin.

Kullanım örneği:

const p1 = Promise.resolve("OK");
const p2 = Promise.reject(new Error(":-("));
const p3 = Promise.resolve(1000);

promiseExecuteAll([p1, p2, p3]).then((data) => {
  data.forEach(value => console.log(`${ value.isSuccess ? 'Resolve' : 'Reject' } >> ${ value.data }`));
});

/* Output: 
Resolve >> OK
Reject >> :-(
Resolve >> 1000
*/

2
Promise.allKendinizi yeniden uygulamaya çalışmayın , yanlış gidecek çok fazla şey var. Örneğin, sürümünüz boş girdileri işlemiyor.
Bergi

-4

Hangi vaat kütüphanesini kullandığınızı bilmiyorum, ama çoğunda böyle bir şey var allSettled .

Düzenleme: Tamam harici kütüphaneler olmadan düz ES6 kullanmak istediğiniz için böyle bir yöntem yoktur.

Başka bir deyişle: Tüm sözler yerine getirilir getirilmez , sözlerinizin üzerinde elle dolaşmanız ve yeni bir birleşik sözün çözümlenmesi gerekir.


Açıklığa kavuşturmak için sorumu düzenledim - ES6 vaatlerle geldiğinden, temel işlevsellik olduğunu düşündüğüm şey için başka bir kütüphane kullanmaktan kaçınmak istiyorum. Sanırım cevap almak için iyi bir yer vaat kütüphanelerinden birinden kaynağı kopyalamak olacaktır.
Nathan Hagen
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.