2016-08-04 23 views
0

Ich muss einen rekursiven Prozess ausführen und die Versprechungen funktionieren nicht so, wie ich will. Dies ist der Code:Versprechen nicht gelöst in einer .each() - Schleife

var openAllLeves = function() { 
    openAll = 1; 
    $.when(openLevels()).then(openAll = 0); 
} 

var openLevels = function() { 
    var promises = [];  
    $('.myClass:not([data-type="T"])').each(function() { 
     var defer = $.Deferred(); 
     $.when(loadLine($(this)).then(promises.push(defer))); 
    }); 
    return $.when.apply(undefined, promises).promise(); 
} 

var loadLine = function (thisObj) { 
    var defer = $.Deferred(); 
    switch(nivel) { 
     case 1: 
      $.when(getPT($(thisObj).attr('data-a'))).then(defer.resolve()); 
      break; 
     case 2: 
      // ... 
    } 
    return defer.promise(); 
} 

var getPT = function (psn) { 
    var defer = $.Deferred(); 
    var payload = { /* parameters... */ }; 
    $.ajax({ 
     url: webmethod, 
     data: payload, 
     type: "POST", 
     contentType: "application/json; charset=utf-8", 
     dataType: "json", 
     timeout: 10000, 
     success: function (data) { 
      $.when(paintPT(data)).then(function() { 
       if (openAll) 
        openLevels(), defer.resolve(); 
      }); 
     } 
    }); 
    return defer.promise(); 
} 

Mein Problem ist, dass openAll der Wertänderungen 0 vor, so in dem Ajax-Funktion Erfolgscode ausgewertet wird nur eine Iteration durchgeführt wird und die Rekursivität nicht getan. Es sieht so aus, als ob es ausgeführt wird, bevor das Array der Versprechen aufgelöst wird.

Der Code ist ein wenig verwirrend, so dass jede Hilfe geschätzt wird. Vielen Dank im Voraus.

+1

können Sie erklären, was dieser Code versucht zu tun? – madalinivascu

+0

Nur versuchen, einen AJAX-Aufruf für jede Zeile in einer Tabelle auszuführen. Diese Aufrufe geben andere Zeilen zurück und generieren neue Aufrufe, bis die zurückgegebene Zeile das Attribut 'data-type = "T"' hat.Danke für Ihr Interesse. – MKP

+0

Können Sie die Tabelle nicht in der serverseitigen Sprache erstellen? Wenn Sie können warum tun Sie es nicht? – madalinivascu

Antwort

1

Vermeiden Sie die deferred antipattern!

Auch wenn Sie etwas zu .then() passieren, muss es Callback-Funktion sein, ruft promises.push(defer), defer.resolve() und openAll = 0 oder so nicht funktioniert, würde es diesen Ausdruck ausführen sofort statt für das Versprechen des Wartens.

Die Aufrufe $.when() und .promise() sind meist überflüssig. Lass sie fallen.

function openAllLeves() { 
    openAll = 1; 
    openLevels().then(function() { 
     openAll = 0 
    }); 
} 

function openLevels() { 
    var promises = [];  
    $('.myClass:not([data-type="T"])').each(function() { // using `map` would be even better 
     promises.push(loadLine($(this))); 
    }); 
    return $.when.apply($, promises); 
} 

function loadLine(thisObj) {; 
    switch(nivel) { 
     case 1: 
      return getPT($(thisObj).attr('data-a')) 
     case 2: 
      // ... 
    } 
} 

function getPT(psn) { 
    var payload = { /* parameters... */ }; 
    return $.ajax({ 
     url: webmethod, 
     data: payload, 
     type: "POST", 
     contentType: "application/json; charset=utf-8", 
     dataType: "json", 
     timeout: 10000, 
    }).then(function (data) { 
     return paintPT(data); 
    }).then(function() { 
     if (openAll) 
      openLevels(); 
    }); 
} 

Btw, Sie wahrscheinlich die if (openAll) openLevels(); auf den Rückgabewert von openLevels() zu verketten wollen, nicht auf jede einzelne Anfrage Versprechen.

1

Ein großes Problem in Ihrem Code ist, dass Sie die Funktionen auf dem dann Rückruf aufrufen und sie nicht daran übergeben. Zum Beispiel:

.then(defer.resolve()); 

diese Weise können Sie den Wert von defer.resolve sind vorbei() zur dann Rückruf und nicht die Funktion, die aufgerufen werden soll, wenn die Asynchron-Aktion beendet. Sie sollten so etwas wie dies tun:

.then(defer.resolve.bind(defer)); 

Das gleiche gilt für den Rest des Codes. Sie sollten bei dem Versprechen einen Blick spec

Besonders

Wenn onFulfilled keine Funktion ist, muss sie ignoriert werden.

EDIT

Wie bereits von Bergi aus sollten Sie die latenten Antipattern vermeiden.

+0

Das ist nicht das eigentliche Problem. – Bergi

+0

Wie so? "Mein Problem ist, dass der Wert von OpenAll sich auf 0 ändert, bevor er in der Ajax-Funktion ausgewertet wird." Ich denke, das ist genau das Problem. Ich habe nicht gesagt, dass das einzige Problem in dieser speziellen Zeile lag. Es war nur ein Beispiel. –

+0

"* Das Problem ist ... *" klingt wie das Problem, dass der Code korrekt funktioniert, wenn er behoben wird. Das verzögerte Antipattern ist jedoch ein viel häufiger auftretendes Problem, und es ist falsch, es nicht zu reparieren. – Bergi

0

Vielen Dank für Ihre Antworten. Ich arbeite an diesen Änderungen. Auf diese Weise verstehe ich, dass .then() nur auf das Versprechen wartet, wenn eine Funktion übergeben wird. So wäre der richtige Weg, um ein Versprechen in .then() zu lösen.

.then(function() { 
    defer.resolve(); 
}) 

¿?

+0

ja, aber wieder, wie Bergi darauf hingewiesen, dass Sie dieses Muster vermeiden sollten, können Versprechen miteinander verkettet werden, nur durch ein neues Versprechen im Callback zurückgeben. –

+0

Vermeiden Sie auch Fragen in einer Antwort zu stellen, verwenden Sie den Kommentarabschnitt dafür –