Ajax-Anfragen queuen

Problem

Sie brauchen eine bessere Kontrolle über die Reihenfolge der vielen unterschiedlichen Ajax-Anfragen.

Lösung

Dieses Rezept stellt zwei verschiedene Wege vor, wie man Ajax-Anfragen queuen kann. Der erste füllt eine Queue mit Anfragen, die dann nacheinander abgesendet werden. Dabei wird die nächste Anfrage immer erst abgeschickt, wenn die Antwort der ersten Anfrage zurückgekommen ist. Der zweite schickt immer eine Gruppe von Anfragen parallel ab. Aber die Callback-Funktionen für jede Anfrage werden immer erst dann ausgeführt, wenn alle Antworten zurückgekommen sind. Zum Vergleich hier ein Beispiel für normale, nicht gequeuete Anfragen:

<!DOCTYPE html>
<html><head>
    <title>jQuery-Kochbuch - 17.5 - Ajax-Anfragen queuen</title>
    <script type="text/javascript" src="jquery-1.3.2.min.js"></script>
    <script type="text/javascript" src="jquery-ajax-queue_1.0.js"></script>
</head>

<body>
    <h1>17.5 - Ajax-Anfragen queuen</h1>
    <input type="button" id="unqueued-requests" value="Nicht gequeuete Anfragen"></input>
    <input type="button" id="queued-requests" value="Gequeuete Anfragen"></input>
    <input type="button" id="synced-requests" value="Synchronisierte Anfragen"></input>
    <p id="response"></p>
</body></html>

Das jQuery-Plugin ajaxqueue (verfügbar unter http://plugins.jquery.com/project/ajaxqueue/) wird genutzt, um das Queueing zu ermöglichen. Drei verschiedene Buttons lösen jeweils eine Gruppe von Ajax-Anfragen aus. In einem Absatz-Element zeigen wir ein Protokoll mit den Antworten an:

(function($) {
    $('document').ready(function() {
        $('#unqueued-requests').click(function() {
            $('#response').empty();
            $.each([1,2,3,4,5,6,7,8,9,10], function() {
                $.get('server.php',{ data: this }, function(data) {
                    $('#response').append(data);
                });
            });
            return false;
        });

Der erste Button löst ganz normale Ajax-Anfragen aus. Es werden zehn Anfragen abgeschickt, wobei jede die Position in der Liste mitschickt. Das Skript server.php simuliert einen Server unter Last, indem er eine zufällige Zeitspanne abwartet, bevor er eine Antwort zurücksendet. Kommt diese an, wird die Anwort an den Inhalt des Absatzes #response angehängt.

        $('#queued-requests').click(function() {
            $('#response').empty();
            $.each([1,2,3,4,5,6,7,8,9,10], function() {
                $.ajaxQueue({url: 'server.php',
                    data: { data: this },
                    success: function(data) { $('#response').append(data); }
                });
            });
            $.dequeue( $.ajaxQueue, "ajax" );
            return false;
        });

Der Button »Gequeuete Anfragen« trägt jede Anfrage in eine Queue ein, indem er die Funktion ajaxQueue() aufruft. Intern wird die Funktion ajax() mit den angegebenen Optionen aufgerufen, wenn eine Anfrage aus der Queue geholt wird. Nachdem alle Anfragen eingetragen wurden, löst ein Aufruf von dequeue() mit der Funktion ajaxQueue als Parameter die erste Anfrage aus. Alle folgenden Anfragen werden anschließend abgearbeitet.

        $('#synced-requests').click(function() {
            $('#response').empty();
            $.each([1,2,3,4,5,6,7,8,9,10], function() {
                $.ajaxSync({url: 'server.php',
                    data: { data: this },
                    success: function(data) { $('#response').append(data); }
                });
            });
            return false;
        });
    });
})(jQuery);

Die letzte Gruppe von Anfragen nutzt die Funktion ajaxSync(), um die Anfragen parallel abzuschicken. Die angegebenen Callbacks werden aber synchronisiert, wenn die Antworten wieder eintreffen.

Diskussion

Antworten von den nicht gequeueten Anfragen kommen in einer nicht vorhersagbaren Reihenfolge zurück. Dieses Verhalten muss nicht unbedingt unerwünscht sein – in vielen Fällen ist es sogar zu bevorzugen. Aber es gibt Szenarien, in denen man mehr Kontrolle über die Ajax-Anfragen und -Antworten haben möchte. Die von ajaxQueue() bereitgestellte Funktionalität ist dann sinnvoll, wenn jede Anfrage von der Antwort der vorherigen Anfrage abhängt, während ajaxSync() dafür genutzt werden kann, Daten zu verändern, die von verschiedenen Servern geholt werden müssen. Dabei kann mit der Verarbeitung erst begonnen werden, wenn alle Server eine Antwort geliefert haben und alle Daten vorhanden sind.

JQuery Kochbuch
titlepage.xhtml
part0000.html
part0001.html
part0002_split_000.html
part0002_split_001.html
part0002_split_002.html
part0003_split_000.html
part0003_split_001.html
part0003_split_002.html
part0003_split_003.html
part0003_split_004.html
part0003_split_005.html
part0003_split_006.html
part0003_split_007.html
part0004_split_000.html
part0004_split_001.html
part0004_split_002.html
part0004_split_003.html
part0004_split_004.html
part0004_split_005.html
part0004_split_006.html
part0004_split_007.html
part0004_split_008.html
part0004_split_009.html
part0004_split_010.html
part0004_split_011.html
part0004_split_012.html
part0004_split_013.html
part0004_split_014.html
part0004_split_015.html
part0004_split_016.html
part0004_split_017.html
part0004_split_018.html
part0005_split_000.html
part0005_split_001.html
part0005_split_002.html
part0005_split_003.html
part0005_split_004.html
part0005_split_005.html
part0005_split_006.html
part0005_split_007.html
part0005_split_008.html
part0005_split_009.html
part0005_split_010.html
part0005_split_011.html
part0005_split_012.html
part0005_split_013.html
part0006_split_000.html
part0006_split_001.html
part0006_split_002.html
part0006_split_003.html
part0006_split_004.html
part0006_split_005.html
part0006_split_006.html
part0006_split_007.html
part0006_split_008.html
part0006_split_009.html
part0006_split_010.html
part0007_split_000.html
part0007_split_001.html
part0007_split_002.html
part0007_split_003.html
part0007_split_004.html
part0007_split_005.html
part0007_split_006.html
part0007_split_007.html
part0007_split_008.html
part0007_split_009.html
part0007_split_010.html
part0007_split_011.html
part0008_split_000.html
part0008_split_001.html
part0008_split_002.html
part0008_split_003.html
part0008_split_004.html
part0008_split_005.html
part0008_split_006.html
part0008_split_007.html
part0008_split_008.html
part0008_split_009.html
part0008_split_010.html
part0008_split_011.html
part0008_split_012.html
part0008_split_013.html
part0008_split_014.html
part0008_split_015.html
part0008_split_016.html
part0008_split_017.html
part0008_split_018.html
part0008_split_019.html
part0008_split_020.html
part0008_split_021.html
part0008_split_022.html
part0009_split_000.html
part0009_split_001.html
part0009_split_002.html
part0009_split_003.html
part0009_split_004.html
part0009_split_005.html
part0009_split_006.html
part0009_split_007.html
part0009_split_008.html
part0009_split_009.html
part0009_split_010.html
part0010_split_000.html
part0010_split_001.html
part0010_split_002.html
part0010_split_003.html
part0010_split_004.html
part0010_split_005.html
part0010_split_006.html
part0010_split_007.html
part0010_split_008.html
part0010_split_009.html
part0010_split_010.html
part0010_split_011.html
part0011_split_000.html
part0011_split_001.html
part0011_split_002.html
part0011_split_003.html
part0011_split_004.html
part0011_split_005.html
part0011_split_006.html
part0011_split_007.html
part0011_split_008.html
part0011_split_009.html
part0011_split_010.html
part0011_split_011.html
part0012_split_000.html
part0012_split_001.html
part0012_split_002.html
part0012_split_003.html
part0012_split_004.html
part0012_split_005.html
part0012_split_006.html
part0012_split_007.html
part0012_split_008.html
part0013_split_000.html
part0013_split_001.html
part0013_split_002.html
part0013_split_003.html
part0013_split_004.html
part0013_split_005.html
part0013_split_006.html
part0013_split_007.html
part0013_split_008.html
part0013_split_009.html
part0013_split_010.html
part0013_split_011.html
part0013_split_012.html
part0014_split_000.html
part0014_split_001.html
part0014_split_002.html
part0014_split_003.html
part0014_split_004.html
part0014_split_005.html
part0014_split_006.html
part0014_split_007.html
part0014_split_008.html
part0014_split_009.html
part0014_split_010.html
part0014_split_011.html
part0015_split_000.html
part0015_split_001.html
part0015_split_002.html
part0015_split_003.html
part0015_split_004.html
part0015_split_005.html
part0015_split_006.html
part0015_split_007.html
part0015_split_008.html
part0015_split_009.html
part0015_split_010.html
part0016_split_000.html
part0016_split_001.html
part0016_split_002.html
part0016_split_003.html
part0016_split_004.html
part0016_split_005.html
part0016_split_006.html
part0016_split_007.html
part0016_split_008.html
part0016_split_009.html
part0017_split_000.html
part0017_split_001.html
part0017_split_002.html
part0017_split_003.html
part0017_split_004.html
part0017_split_005.html
part0017_split_006.html
part0017_split_007.html
part0017_split_008.html
part0017_split_009.html
part0017_split_010.html
part0017_split_011.html
part0018_split_000.html
part0018_split_001.html
part0018_split_002.html
part0018_split_003.html
part0018_split_004.html
part0018_split_005.html
part0018_split_006.html
part0019_split_000.html
part0019_split_001.html
part0019_split_002.html
part0019_split_003.html
part0019_split_004.html
part0019_split_005.html
part0019_split_006.html
part0019_split_007.html
part0019_split_008.html
part0019_split_009.html
part0019_split_010.html
part0020_split_000.html
part0020_split_001.html
part0020_split_002.html
part0020_split_003.html
part0020_split_004.html
part0020_split_005.html
part0020_split_006.html
part0020_split_007.html
part0020_split_008.html
part0021_split_000.html
part0021_split_001.html
part0021_split_002.html
part0021_split_003.html
part0021_split_004.html
part0021_split_005.html
part0021_split_006.html
part0021_split_007.html
part0021_split_008.html
part0021_split_009.html
part0022.html
part0023.html
part0024.html
part0025.html