2017-11-26 4 views
1

Ich erzeuge Objekte mit externen Quellen mit der Absicht, sie Callback-Stil zu verarbeiten. Leider können diese Callbacks weit über das Stacklimit eines Browsers hinausreichen und ich muss das Worst-Case-Szenario von 500 für IE berücksichtigen.

Ich habe meinen Code neu geschrieben $ Frage: Wann

$scope.combinations.forEach(function(combination) { 
     chain = chain.then(function() { 
     return generateConfiguration(combination); 
     }); 
    }); 

generateConfiguration wenn eine Funktion, die ein Versprechen zurück. Es funktioniert alles gut, aber was ich tun möchte, ist schließlich() am Ende der Kette hinzuzufügen.

Was ich bis jetzt getan habe, ist ein Tracker in generateConfiguration zu haben, der die letzte Kombination erkennt und auslöst, was durch schließlich ausgelöst werden sollte.

Gibt es einen saubereren Weg, es zu tun?

+0

Schreib einfach 'chain.finally (...)' nach der Schleife? – Bergi

Antwort

1

Es hängt davon ab, was Sie tun möchten.

Sie erstellen ein Versprechen Kette, wenn Sie also ein einzelnefinally für die Kette wollen, nur um es am Ende hinzufügen, nachdem es mit diesen forEach Aufbau:

// ...your forEach here, then: 
chain.finally(/*...*/); 

Wenn Sie wollen ein finally auf jeder Versprechen von generateConfiguration, entweder geben Sie sich eine Wrapper-Funktion, um dies zu tun, oder tun Sie es innerhalb der forEach Rückruf.

$scope.combinations.forEach(function(combination) { 
    chain = chain.then(function() { 
     return generateConfiguration(combination).finally(/*...*/); // <== 
    }); 
}); 

Randbemerkung: Es gibt einen mehr idiomatischen Weg, um die Kette zu bauen, über reduce:

var chain = $scope.combinations.reduce(function(chain, combination) { 
    return chain.then(function() { 
     return generateConfiguration(combination); 
    }); 
}, Promise.resolve()); 

eine endgültige finally (Option # 1 oben) Hinzufügen:

var chain = $scope.combinations.reduce(function(chain, combination) { 
     return chain.then(function() { 
      return generateConfiguration(combination); 
     }); 
    }, Promise.resolve()) 
    .finally(function() { 
     // ...do stuff here... 
    }); 
+1

@TJ Danke, dass deine anfängliche Lösung funktioniert. Nicht sicher, warum ich es nicht gerade versucht habe. Über Ihren Vorschlag, warum ist es besser als meine Lösung? – CountGradsky

+0

@CountGradsky: Es ist nicht * besser * anders als dass es das Idiom für das ist, was in den letzten 3-4 Jahren entstanden ist.:-) Idiome sind "gut" oder "besser" nur dadurch, dass sie für andere Programmierer leicht erkennbar sind, die auch das Idiom kennen und den Code leicht verständlich machen. –

+0

Nicht ein Muttersprachler, musste googeln "idiomatic" :) Ich werde Ihren Vorschlag als Kommentar haben, wenn Sie nichts dagegen haben – CountGradsky

0

Ja, es gibt: injizieren $q (dh das Versprechen Rahmen) und REW-rite zu

$q.all($scope.combinations.map(function(combination) { 
    return generateConfiguration(combination); 
})).finally(function(res) { 
    /* ... */ 
}); 

Auf diese Weise werden Sie auch alle generateConfiguration (s) parallel (zumindest so viele abfeuern wie möglich - wie zB XHR). Anyways: $q.all(arrayOfPromises) könnte das sein, was Sie gesucht haben.

+1

Ändert das nicht, was der Code tut? Der Code des OP behandelt die Versprechen * seriell *. Behandelt "$ q.all" sie nicht * parallel (wie der Standard "Promise.all", von dem ich glaube, dass er von qs inspiriert wurde)? –

+0

$ q.all funktioniert nicht für mich in diesem Szenario Seb – CountGradsky

+2

ja, wie gesagt, es behandelt sie parallel. Wenn das wirklich nicht gewünscht ist, würde ich einfach .finally auf den letzten Wert von .chain aufrufen (wie bereits in einer anderen Antwort vorgeschlagen) –

Verwandte Themen