2016-03-29 5 views
0

Ich weiß, dass das A in AJAX asynchrone bedeutet, und als solche gibt es keine Garantie, in welcher Reihenfolge meine Antworten zurückkommen, in der Tat ist die größte Payload vernünftig zu erwarten als letztes zurückkommen.Wie ruft JavaScript/Callback-Funktionen auf mehrere AJAX-Antworten

Meine Frage betrifft jedoch die Rückrufe. Manchmal, wenn ich bemerke, dass meine Antworten in einer anderen Reihenfolge, in die sie gesendet wurden, zurückkommen, wird der "falsche" Rückruf aufgerufen.

Nehmen Sie die folgende Funktion. Es gibt einige Werte (rangesize, dropskus, limit) (kommentiert unten), die für jeden Aufruf eindeutig sind und im Erfolgsrückruf für jeden definiert sind. Wenn ich das Skript ausführen und 5 Anrufe senden, wenn sie in einer anderen Reihenfolge zurückkommen, an die sie gesendet wurden. Nehmen wir an, die größte Antwort war der 2. Aufruf, die Antwort kommt als letzte zurück und ruft auch die letzte Callback-Funktion auf.

Also meine Frage:

Does oder sollte JavaScript/jQuery wissen, welche Callback-Funktion aufzurufen, wenn mehrere Antworten zurückkehrt?

Oder wäre es besser für mich synchrone Anrufe zu verwenden?

Andere Notizen: Beim Debuggen in Chrome habe ich festgestellt, dass die Konsolenprotokolle der Antworten sagen filename.js:linenumber. Während zuvor, wenn ich mehrere Ajax-Aufrufe verwendet habe, die Konsolenprotokolle sagen VM12*:linenumber. Ich weiß nicht, ob das etwas mit dem Problem zu tun hat, mit dem ich konfrontiert bin, aber ich habe bemerkt, dass in diesem Fall immer die richtigen Callbacks aufgerufen wurden.

function generateReview(){ 

    var subcategories = subcatstring.split(","); 

    $("#rangereviewtable").html(""); 
    $("#rangereviewtable").append(thead); 

    var i = 0; 
    var iterations = subcategories.length; 
    $.each(subcategories, function(key, value) { 

     var postdata = {group: group, 
         class: rrclass, 
         category: category, 
         subcategory: value, 
         period: period, 
         periodval: periodval, 
         stores: storesarray}; 
     console.log(postdata); 

     $.ajax({ 
       url: "ajaxrangereview.php", 
       type: "post", 
       dataType: 'json', 
       data: postdata, 
       success: function (response) { 

        //VALUES UNIQUE TO EACH CALL 
        var rangesize = parseInt($("#rangesize" + i).text()); 
        console.log("range size: " + rangesize); 
        var dropskus = parseInt($("#dropskus" + i).text()); 
        console.log("dropskus: " + dropskus); 
        var limit = rangesize - dropskus; 
        console.log("limit: " + limit); 

        console.log(response); 

        var rrtable = ""; 

         $.each(response, function(i, item) { 

          rrtable += "<tr>"; 
           rrtable += "<td class='rangereviewtext'>" + item.category + "</td>"; 
           rrtable += "<td class='rangereviewtext'>" + item.subcategory + "</td>"; 
           rrtable += "<td class='rangereviewtext'>" + item.brand + "</td>"; 
           rrtable += "<td class='rangereviewtext'>" + item.sku + " - " + item.product + "</td>"; 
           rrtable += "<td class='rangereviewnumber'>" + item.py3.toLocaleString("en") + "</td>"; 
           rrtable += "<td class='rangereviewnumber'>" + item.py2.toLocaleString("en") + "</td>"; 
           rrtable += "<td class='rangereviewnumber'>" + item.py1.toLocaleString("en") + "</td>"; 
           rrtable += "<td class='rangereviewnumber'>" + item.average.toLocaleString("en") + "</td>"; 
           rrtable += "<td class='rangereviewnumber'>" + item.sales.toLocaleString("en") + "</td>"; 
           rrtable += "<td class='rangereviewnumber'>" + item.share + "%</td>"; 
           rrtable += "<td>&#x2714</td>"; 

           if(limit >= item.idnum){ 

            rrtable += "<td>&#x2714</td>"; 
            rrtable += "<td class='checkboxcell' onClick=\"toggleCheckMark(this, '" + item.brand + "')\">&#x2714</td>"; 

           } else { 

            rrtable += "<td></td>"; 
            rrtable += "<td class='checkboxcell' onClick=\"toggleCheckMark(this, '" + item.brand + "')\"></td>"; 

           } 

          rrtable += "</tr>"; 
         }); 
        // increment iterations 
        i += 1; 

        $("#rangereviewtable").append(rrtable); 

        if(i == iterations){ 

         var headimage = "<img src='http://url.com/images/oimage.png' width='63.5px' height='76px'>"; 
         var table = $("#rangereviewtable").DataTable({ 
                    buttons: [{extend: 'excelHtml5', title: 'Range Review', text: 'Export to Excel'}, 
                       {extend: 'print', title: 'Range Review', message: headimage}], 
                    }); 
         //insert export to excel button into #rrbuttons div above actual table. 
         table.buttons().container().appendTo($('#rrbuttons')); 

         $("#rangereviewpanel").show(); 
         $("#generatebutton").hide(); 
         $("#loadbutton").hide(); 
         $("#saveasbutton").show(); 
         generateReviewSummary(summaryarray); 

        } else { 

         //do nothing not all iterations complete 

        } 

        }, 
       error: function(jqXHR, textStatus, errorThrown) { 

        i+= 1; 
        console.log(textStatus, errorThrown); 
        } 
      }); 
    }); 
} 

Antwort

1

In Ihrem speziellen Fall finde ich es gut funktionieren wird (Ihr Code tut so etwas wie):

var j = 0; 
for (var i = 0; i < 10; i++) { 
    setTimeout(function() { 
     console.log(j); 
     j++ 
    }, 1000) 
} 

Dieser Code wird 0..9 Zahlen ausgibt;
Aber lassen Sie ein anderes Beispiel sehen:

for (var i = 0; i < 10; i++) { 
    setTimeout(function() { 
     console.log(i); 
    }, 1000) 
} 

Es gibt 9..9
So ist es nicht sicher Ansatz asynchrone Funktionen innerhalb Synchronschleife zu nennen. Sie können async.each (https://github.com/caolan/async#each) verwenden oder verspricht, damit umzugehen.

+0

Ich denke, vielleicht Versprechen könnte etwas für mich zu sehen sein. aber da ich wieder an meinen Tisch anschließe, bis alle Anrufe abgeschlossen sind und trotzdem zurückkommen, ist es kein Problem Async: false zu benutzen. Ich will nur nicht, dass synx xhr veraltet Fehler! Danke, dass Sie sich die Zeit genommen haben, zu antworten. –

+0

@AdamCopley Ok, ich habe es verstanden. Sie möchten warten, bis alle Anfragen erledigt sind? Sie können async.each (Verknüpfung von Antwort) verwenden.Der letzte Rückruf wird bei jeder Anfrage ausgeführt. Und es ist viel besser als 'async: false', weil alle Anfragen immer noch parallel sind. –

+0

Die Art, wie ich es habe, ist, dass ich möchte, dass die Callback-Funktion einige ihrer eigenen Sachen zur Antwort macht (Berechnungen mit Rangesize, Dropskus und Limit), bevor es an die Variable 'rrtable' angehängt wird. Wenn alle Aufrufe abgeschlossen sind, fügen Sie die rrtable-Zeichenfolge an die HTML-Tabelle an. –

1

JavaScript/jQuery weiß genau, welcher Callback aufgerufen werden soll und tut dies auch richtig.

Sie müssen mehr über JavaScript-Verschlüsse und Umfang erfahren.

Ich bin nicht sicher, was Sie mit "falsch" und "richtig" Rückruf im Hinblick auf Ihre Logik bedeuten. Wenn Sie möchten, dass die Sonderlogik einläuft, wenn Sie die Antwort auf die letzte Anfrage erhalten, dann könnten Sie vielleicht versuchen, Ihre Verwendung von i durch Verweise auf key zu ersetzen (oder wenn ich Ihre Logik richtig lese, Sie könnte key + 1 verwenden)

+0

Vielleicht ist der Umfang das Problem. Ich werde den Schlüssel anstelle von "i" verwenden, weil sie den gleichen Wert haben, aber das ist klein. Ist es nicht korrekt, dass die anonyme Funktion, die in 'success:' definiert ist, und die Werte ihrer Variablen gespeichert werden, bis die spezifische Antwort empfangen wird? –

+0

Die lokal deklarierte Variable 'postdata' zusammen mit den Funktionsargumenten' key' und 'value' sind Teil der Closure für den Callback. Variablen wie "i" sind Teil der Geltungsbereichskette und können sich ändern. MDN hat einen schönen Artikel über Schließungen: https://developer.mozilla.org/en/docs/Web/JavaScript/Closures – searlea

+0

'i' wird nicht den gleichen Wert wie Sie nicht garantieren, in welcher Reihenfolge die Async-Aufrufe werden vom Webserver ausgeführt/zurückgegeben. – Hydrospanners

Verwandte Themen