2017-11-13 1 views
2

Ich glaube nicht, das mit der nativen Versprechen Implementierung möglich ist, aber hier ist die grundlegende Idee von dem, was ich will:Wie auf Promise.all schieben (Array)

const promises = [ 
    getSomething(), 
    getSomethingElse(), 
]; 

// combine promises 
const alldone = Promise.all(promises); 

// Add a promise after the previous ones have started 
promises.push(getAThirdThing()); 

// everything, including `getAThirdThing` is done 
await allDone; 

In Wirklichkeit Promise.all() nicht Sorge dafür, dass ich etwas auf das promises Array geschoben habe.

Gibt es ein ähnliches Muster, das dasselbe bewirkt? Genauer gesagt, das Hinzufügen anderer Versprechen, auf die gewartet werden muss, wie sie einer Liste derzeit ungelöster Versprechen bekannt werden, ohne dass später etwas hinzugefügt werden muss.

ich so etwas wie dies stattdessen tun könnte:

const promises = [ 
    getSomething(), 
    getSomethingElse(), 
]; 
const alldone = Promise.all(promises); 
await Promise.all([alldone, getAThirdThing()]); 

Aber ich möchte das Hinzufügen getAThirdThing().then() auf allDone vor rufen.

Antwort

1

Um Versprechen auf eine Reihe von Versprechungen hinzufügen und sie auf ein Versprechen warten alle mit der Fähigkeit erfüllt, werden zusätzliche Versprechungen zu dem Satz hinzuzufügen, gibt es mindestens zwei Möglichkeiten:

  1. erstellen ein onFulfilled-Handler, aufgerufen von then, der prüft, ob weitere Versprechungen darauf warten, hinzugefügt zu werden, und wenn dies der Fall ist, eine Versprechung für sie (alle) zu verketten an eine andere Versprechung, die denselben then-Handler verwendet. Dies entspricht mehr oder weniger einer rekursiven asynchronen Methode, die Versprechen hinzufügt, sofern sie verfügbar sind. Das Nachvollziehen der erfüllten Ergebnisse und das Abgleichen mit Versprechensoperationen sowie das Vermeiden von Fehlern bei der Zurückweisung von Abrufen würden immer noch Aufmerksamkeit erfordern.

  2. Schreiben Sie eine benutzerdefinierte statische Promise-Methode oder -Konstruktor, die stattdessen die gewünschten Funktionen ausführt, ohne Promise.all zu verwenden.

Als Beispiel 2. kehrt der PromiseGroup Konstruktor unten ein Objekt mit

  • a promise` Eigenschaft, die mit einer Reihe von Werten in der Reihenfolge Versprechungen wurden hinzugefügt, um die Gruppe angesiedelt ist, und
  • eine add Methode, die verspricht, in der Reihenfolge der Präsentation abgerechnet werden.

function PromiseGroup() { 
 
    var resolve; 
 
    var reject; 
 
    this.promise = new Promise((r, j) => { resolve = r, reject = j}); 
 
    this.settled = false; 
 

 
    const group = this; 
 
    var numAdded = 0; 
 
    var numSettled = 0; 
 
    const values = []; 
 
    const quickReject = reason => reject(reason); 
 
    const fulfill = (i, value) => { 
 
     values[i] = value; 
 
     if(++numSettled === numAdded) { 
 
      resolve(values); 
 
      group.settled = true; 
 
     } 
 
    }; 
 
    this.add = function() { 
 
     if(group.settled) { 
 
      console.trace(); 
 
      throw new Error("Can't add promises to a settled group"); 
 
     } 
 
     for(var j = 0; j < arguments.length; ++j) { 
 
      let i = numAdded + j; 
 
      Promise.resolve(arguments[j]) 
 
      .then(value => fulfill(i, value), quickReject); 
 
     } 
 
     numAdded += j; 
 
    }; 
 
} 
 

 
//********************************************  and test: 
 

 
async function test() { 
 
    var group = new PromiseGroup(); 
 
    group.add(new Promise(resolve=> setTimeout(resolve=>resolve(1), 500, resolve)), 
 
      new Promise(resolve=> setTimeout(resolve=>resolve(2), 600, resolve))); 
 
    setTimeout(test2, 100, group); 
 
    var values = await group.promise; 
 
    // some more code 
 
    return values 
 
} 
 

 
function test2(group) { // add more after await 
 
    group.add(new Promise(resolve=> setTimeout(resolve=>resolve(3), 700, resolve)), 
 
      new Promise(resolve=> setTimeout(resolve=>resolve(4), 400, resolve))); 
 
} 
 

 
test().then(values=>console.log(JSON.stringify(values)));

Der Grund für diese Antwort ist, dass Promise.all und Promise.race sind minimal und Low-Level-Set verheißungsAggregationsVerfahren und ihre Präsenz müssen, um die Entwicklung neuer nicht auszuschließen.

Die Weisheit der Verwendung PromiseGroup oder ähnlich ist eine separate Überlegung. Persönlich würde ich das gesamte asynchrone Design der Anwendung überprüfen, um zu sehen, ob optionale Versprechen mit Versprechen Operationen kombiniert werden könnten, die ihren Bedarf bestimmen, wenn möglich, bevor jemals die Promise.all oder Gruppenphase erreicht.

+0

Ich habe die erste Option verwendet und es hat sehr gut funktioniert und hat nicht viel Komplexität hinzugefügt. Danke für Ihre Hilfe :) –

2

Promise.all gibt ein Versprechen selbst, so können Sie Promise.all nacheinander aufrufen:

let finished = Promise.all([...]); 
finished = Promise.all([finished, someFunctionReturningAnotherPromise()]); 
finished = Promise.all([finished, anotherFunctionReturningAPromise()]); 
// etc... 
// finally: 
await finished; 

jedoch, was Sie nicht tun ist, um die Versprechen Kette hinzufügen nachawait das Versprechen von Promise.all zurück ing .

Auch werden die Dinge ein wenig kompliziert, wenn in diesem Szenario, wenn Sie die Ergebnisse alle die Versprechungen zugreifen möchten, wie Sie mit verschachtelten Arrays der Ergebnisse würden am Ende (die man so etwas wie lodash.flattenDeep verwenden könnte normalisieren sie).