2014-04-14 3 views
15

Ich habe bereits mit Promises herumgespielt, aber ich bin neu für sie und ich kann einfach nicht herausfinden, wie es richtig geht. Im Moment hat das Promise keinen Sinn, denn es wartet nicht bis der asynchrone $.get abgeschlossen ist.Wie kann ich diese asynchrone foreach-Schleife mit Versprechen arbeiten lassen?

Grundsätzlich jede foreach Iteration hat seine eigene $.get Funktion, und ich brauche sie alle vollständig und dann weiter zum Teil zu haben, die hat console.log „... AlbumArt bekommt“.

$.get(id,function(data) { 
    //(there's some code here) 
    var getZippyUrls = new Promise(function(resolve) { 
      zippyarray.forEach(function(zippy) { 
      //(more code) 
      $.get(zippy.full, function(data) { 
       //^This is the foreach of $.gets 
       //(code's here) 
      }); 
      resolve(zippyarray); 
     }); 
    }); 

    //This is my failed Promise -> 
    getZippyUrls.then(function(response) { 
     console.log("WE'RE OUT " + response.length); 
     response.foreach(function(d) { 
      console.log("Promise"+d.media); 
     }); 
     console.log('eyyyyyy'); 
    }); 

    console.log("...gets albumart"); 
    //Now after the previous stuff is done, move on 
+0

Regel mit so viel Code Leute nicht einmal die Mühe, Ihre Frage zu lesen. –

+1

Mutter des Codes! – Arthur

+0

Sie müssen nicht die ganze Sache lesen, die grundlegende Frage ist die gleiche - es gibt eine foreach-Schleife mit $ .get-Funktionen, und ich brauche sie alle zu vervollständigen, bevor Sie weitermachen. Ich werde den Code tho verkürzen, denke ich ... – Fabis

Antwort

20

Im Synchroncode, Fortsetzung durchgeführt wird, wenn die Leitung ;

mit dem Versprechen endet, wird die Fortsetzung über .then durchgeführt. Sie haben einen Versprechenskonstruktor verwendet und ihn sofort gelöst. Sie haben auf keine Aufgabe gewartet. Ich würde meine Arbeit in Aufgaben unterteilen und sie dann entweder verketten oder seriell erwarten.

//I'm assuming 
zippyarray; // array of Zippy objects 

var tasks = zippyarray.map(function(zippy,i){ 
    return function(){ // return a task on that zippy; 
     // basic logic here 
     return $.get({ 
      // ajax request 
     }).then(function(data){ 
      // process data like in your code 
      // possibly store later for later use too 
      return process(data); // return the processed data; 
     }); 
    } 
}); 

Jetzt können wir sie alle der Reihe nach ausgeführt werden:

var p = tasks[0](); // start the first one 
for(var i = 1; i < tasks.length; i++) p = p.then(tasks[i]); 
p.then(function(result){ 
     // all available here 
}); 

Oder besser, seriell:

$.when.apply(tasks.forEach(function(t){ return t(); })).then(function(results){ 
    // all done 
}) 
+0

Ich verstehe nicht, warum gibt es 3 gibt innerhalb der map() -Funktion zurück. Könntest du das für mich klären? Was macht jeder von ihnen? – Fabis

+0

@Fabis die äußere Rückkehr gibt die Aufgabe zurück. Wir ordnen jedes Zippy einer Funktion zu. Die zweite Rückgabe kommt von der Task-Funktion und gibt das Ergebnis von $ .get (ein Versprechen) zurück. Die dritte Rückgabe ist die Rückgabe eines Wertes von einem '.then'-Handler. Wenn Sie einen Wert aus einem then-Handler zurückgeben, wird im Allgemeinen das Versprechen mit diesem Wert aufgelöst. Wenn es sich bei diesem Wert um ein Versprechen handelt, wird das äußere Versprechen mit seinem unverpackten Wert aufgelöst. –

+0

Wenn ich 'return process()' verwendet habe, dann bekomme ich den Fehler: 'Unhandled Ablehnung TypeError: Eigenschaft 'Prozess' von Objekt # ist keine Funktion' Lässt mich denken, ich sollte keine Prozessfunktion verwenden, wenn zurückgeben Array von Objekten –

0

Spur zu halten von mehreren Get-Requests Sie auf diese Weise verwenden:

var cnt = requestCnt; 

function finished(){ 
    if(--cnt)return; 
    // Your code here 
} 

for(var i = 0; i < requestCnt; ++i){ 
    $.get('something.htm', {data:data}, function(data){ 
     finished(); 
    }); 
} 

Sie nennen immer die Finishe d-Funktion, wenn eine Anfrage eine Antwort erhält. Die fertige Funktion erledigt den Job, wenn alles erledigt ist.

+1

Dies ist manuell implementieren Logik, die bereits mit Versprechen besteht. Es heißt ein asynchroner Semaphor BTW. –

+0

Schön, den Namen zu kennen. Es ist nie falsch, den Code hinter der Funktion zu kennen. Vor allem, wenn Sie die jquery-lib auf Ihrer Seite haben – Fuzzyma

+0

Sie brauchen nicht die jQuery-Bibliothek, können Sie entweder einen modernen Browser (Versprechen sind ein Teil der neuen ES6-Spezifikation), oder eine gute Versprechen Bibliothek (wie Bluebird) . Wenn Sie dies manuell tun, ignoriert Ihr Code eine Menge Dinge (Fehlerbehandlung usw.). Es könnte als '$ .when.apply geschrieben werden (requests.map (function (el) {return $ .get (" something.html ", {data: el});})). Then (function (results) {/* Ergebnisse alle hier verfügbar * /}); ' –

10

Ich weiß, das ist eine alte Frage, aber die Dinge haben sich in letzter Zeit etwas geändert.

Wenn Sie mit externen Bibliotheken in Ordnung sind, hat die Bluebird Versprechen-Bibliothek eine ziemlich gute Implementierung dafür: Promise.each.

z.

function helperFunc(zippyarray) { 
    return Promise.each(zippyarray, zippy => { 
    return someOperationThatReturnAPromise(zippy) 
     .then((singleResult) => { 
     // do something with the operation result if needed 
     }) 
    }).then((originalArray) => { 
    // this happens only after the whole array is processed 
    // (result is the original array here) 
    return Promise.resolve(originalArray) 
    }) 
} 
+0

Hallo, kannst du ein anderes Beispiel geben, ohne bluebird zu benutzen? Ich brauche nur Promise.each. Mit bluebird habe ich eine große kompilierte Datei bekommen. Es ist nicht gut –

+0

Wenn Sie keine Bibliotheken verwenden möchten (möglicherweise abgesehen von jQuery, das in der Frage selbst verwendet wird), denke ich, dass Benjamins Antwort der richtige Weg sein könnte. Oder wenn Sie ES6 verwenden, können Sie alle gewünschten Funktionsaufrufe in einer Sammlung hinzufügen und dann 'Promise.all' damit verwenden. – MJV

0

Heute, wenn ich brauchte es der Reihe nach zu tun - ich habe es mit async/await tun würde:

//I'm assuming I'm inside an `async` function 
zippyarray; // array of Zippy objects 

for(const task of zippyArray) { 
    const result = await $.get({ ... }); 
    // do stuff with result 
}