wake-up-neo.com

Verwendung von Promise in der forEach-Schleife eines Arrays zum Auffüllen eines Objekts

Ich führe eine forEach-Schleife für ein Array aus und mache zwei Aufrufe, die Versprechen zurückgeben, und ich möchte ein Objekt mit this.options füllen und dann andere Dinge damit erledigen. Im Moment laufe ich in die asynchrone Ausgabe, wenn ich das folgende Codebeispiel verwende, und ich komme zuerst in die then-Funktion.

$.when.apply($, someArray.map(function(item) {
    return $.ajax({...}).then(function(data){...});
})).then(function() {
    // all ajax calls done now
});

Dies ist der folgende Arbeitscode, aber er funktioniert nur für das erste Element im Array, da ich die resultierende Funktion im .then der Antwort aufrufe. Ich möchte den gesamten Abruf zuerst für alle Elemente des Arrays durchführen und dann die resultierende Funktion aufrufen, um etwas zu tun.

array.forEach(function(element) {
    return developer.getResources(element)
        .then((data) = > {
            name = data.items[0];
            return developer.getResourceContent(element, file);
        })
        .then((response) = > {
            fileContent = atob(response.content);
            self.files.Push({
                fileName: fileName,
                fileType: fileType,
                content: fileContent
            });
            self.resultingFunction(self.files)
        }).catch ((error) = > {
            console.log('Error: ', error);
        })
});

Wie fülle ich das self.files-Objekt, nachdem die forEach-Schleife abgeschlossen ist, und rufe dann die resultierende Funktion mit dem files-Objekt auf? 

14
rond

Promise.all() wird hier hilfreich sein:

var promises = [];

array.forEach(function(element) {
    promises.Push(
        developer.getResources(element)
            .then((data) = > {
                name = data.items[0];
                return developer.getResourceContent(element, file);
            })
            .then((response) = > {
                fileContent = atob(response.content);
                self.files.Push({
                    fileName: fileName,
                    fileType: fileType,
                    content: fileContent
                });
            }).catch ((error) = > {
                console.log('Error: ', error);
            })
    );
});

Promise.all(promises).then(() => 
    self.resultingFunction(self.files)
);

Dies startet den Aufruf von AJAX für jedes Element, fügt das Ergebnis jedes Aufrufs zu self.files hinzu, sobald der Anruf abgeschlossen ist, und ruft self.resultingFunction() auf, nachdem alle Aufrufe abgeschlossen wurden.

Bearbeiten: Vereinfacht basierend auf den Vorschlägen von Yury Tarabanko.

45
Timo

Nur eine geringfügige Abweichung von der oben akzeptierten Lösung wäre:

var promises = array.map(function(element) {
      return developer.getResources(element)
          .then((data) = > {
              name = data.items[0];
              return developer.getResourceContent(element, file);
          })
          .then((response) = > {
              fileContent = atob(response.content);
              self.files.Push({
                  fileName: fileName,
                  fileType: fileType,
                  content: fileContent
              });
          }).catch ((error) = > {
              console.log('Error: ', error);
          })
});

Promise.all(promises).then(() => 
    self.resultingFunction(self.files)
);
14
IonicBurger

Der folgende Code ist ein einfaches Verständnis der Synchronisierung mit Promise.

let numArr = [1,2,3,4,5];
let nums=[];

let promiseList = new Promise(function(resolve,reject){
  setTimeout(()=>{
        numArr.forEach((val)=>{
        nums.Push(val);
    });
    resolve(nums);
 },5000)
})


Promise.all([promiseList]).then((arrList)=>{
  arrList.forEach((array)=>{
    console.log("Array return from promiseList object ",array);    
  })

 });

Das obige Beispiel hält array nums für 5 Sekunden. und es wird nach der Veröffentlichung auf der Konsole gedruckt. 

1
jasmeetsohal

Sie könnten diese Antwort auf eine ähnliche Frage nach einem ausgezeichneten Hinweis betrachten. Die dort gegebene Lösung verwendet Array#reduce(), um zu vermeiden, dass alle Versprechungen gesammelt werden müssen, bevor eine Arbeit ausgeführt wird, anstatt Promise.all() zu verwenden.

1
Alan Mimms