[AJAX] Meerdere asynchrone requests

Pagina: 1
Acties:
  • 304 views sinds 30-01-2008
  • Reageer

  • Scorpion1984
  • Registratie: Juni 2002
  • Laatst online: 13-02 12:30
Ik heb op allerlei manieren al geprobeerd om meerdere asynchrone ajax requesten te verzenden en te verwerken. Ik heb dit nodig voor een pagina waarbij meerdere xmlhttprequest objecten geen optie is (dan worden het namelijk een stuk of 50 tot 100 objecten).

Ik had daarom gedacht om te werken met een soort stack, dit werkt goed in internet explorer en firefox, maar om een of andere reden niet in opera. Weet iemand een andere oplossing, of ziet mijn fout? Ik heb al uitgebreid gezocht, maar ik vond geen werkende oplossing(wel een firefox-only oplossing).

De globals voor het begin van het object is niet netjes, dat weet ik, maar het probleem is dat de functie triggerFunction niet de object variabelen aankan.

Mijn testscript:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<html>
    <head>
    <script src="ajaxObject3.js"></script>
        <script>

    var dinges = lala;

function lala(requestObj, customData)
{
    document.getElementById("asd").innerHTML += "(" + customData + "): " + requestObj.responseText + "<br />";
}


        </script>
    </head>
    <body>
        <div id="asd">
        </div>
    </body>
    <script>
for(var i=0; i<10; i++) {

    customData = i+1;
    ajax.addRequest("tester.php?id=" + i, lala, customData)
    ajax.id = i;    
};
    </script>
</html>


Mijn javascript code:
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
var requestObject = false;
var requestData = new Array();
var running = false;
var ajax = new AJAX();
function AJAX()
{   
    // Create requestObject
    if (window.XMLHttpRequest)
    {
        requestObject = new XMLHttpRequest();
    }
    else if (window.ActiveXObject) // Internet Explorer
    {
        requestObject = new ActiveXObject("Microsoft.XMLHTTP");
    }
    
    // Add RequestData
    this.addRequest = function(url, triggerFunction, customData, postData)
    {
        nr = requestData.length;
        requestData[nr] = new Array();
        requestData[nr]["url"] = url;
        requestData[nr]["triggerFunction"] = triggerFunction;
        requestData[nr]["customData"] = customData;
        requestData[nr]["postData"] = postData;
        
        // If RequestData isn't processed, start it now
        if (!running)
            this.processRequests();
    }
    
    // Processes the responses of the server
    this.triggerFunction = function()
    {
        if (requestObject.readyState == 4)
        {
            requestData[0]["triggerFunction"](requestObject, requestData[0]["customData"]);         
            
            requestData.shift();
            if (requestData.length > 0)
                ajax.processRequests();
            else
                running = false;
        }
    }
     
    // Processes the requestData
    this.processRequests = function()
    {
        running = true;
        url = requestData[0]["url"];
        postData = requestData[0]["postData"];
        if (requestObject)
        {
            if (postData == null)
                requestObject.open('GET', url, true);
            else
                requestObject.open('POST', url, true);

            requestObject.onreadystatechange = this.triggerFunction;
            requestObject.send(postData);
            requestObject.onreadystatechange = this.triggerFunction;
        }
        else
        {
            return false;
        }
    }
}

[ Voor 10% gewijzigd door Scorpion1984 op 08-04-2006 16:58 ]


  • Michali
  • Registratie: Juli 2002
  • Laatst online: 09-12-2025
Je zult toch echt meerdere XMLHttpRequest objecten moeten maken, en dat is zeker wel een optie. Dat het er 100 zijn maakt echt niet zo veel uit. Daarbij zul je echt geen performance problemen krijgen.

Lijkt me overigens sterk dat dit werkt. Je pakt iedere keer de eerste request in processRequests, lijkt me niet echt de bedoeling.

[ Voor 26% gewijzigd door Michali op 08-04-2006 14:13 ]

Noushka's Magnificent Dream | Unity


  • Scorpion1984
  • Registratie: Juni 2002
  • Laatst online: 13-02 12:30
Michali schreef op zaterdag 08 april 2006 @ 14:11:
Je zult toch echt meerdere XMLHttpRequest objecten moeten maken, en dat is zeker wel een optie. Dat het er 100 zijn maakt echt niet zo veel uit. Daarbij zul je echt geen performance problemen krijgen.

Lijkt me overigens sterk dat dit werkt. Je pakt iedere keer de eerste request in processRequests, lijkt me niet echt de bedoeling.
Het werkt volledig, behalve om een onbekende reden in Opera. Je pakt wel iedere keer de eerste request in processRequest, maar die is elke keer anders, aangezien ik de eerste erafkap met de functie shift() en de rest naar voren schuif.

Met meerdere XMLHttpRequest objecten is ook geen optie, omdat je dan in de functies die het verwerkt niet weet welk object je moet gebruiken (Het zal namelijk meer dan 1 object zijn per verwerk-functie). Daarnaast zal de code ook een rotzooi worden.

[ Voor 4% gewijzigd door Scorpion1984 op 08-04-2006 18:00 ]


Verwijderd

Dat hoeft niet, waarom moeten je functies weten welk object ze gebruiken? Je maakt een factory, die je aanroept en die de objecten teruggeeft. That's all.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function getXMLParser(){
    if (getXMLParser.type){
        return getXMLParser.type;
    }
    
    var types = ['Microsoft.XMLHTTP','MSXML2.XMLHTTP.5.0','MSXML2.XMLHTTP.4.0','MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP'];
    for (var i=0;i<types.length;i++) {
        try {
            new ActiveXObject(types[i]);
            return getXMLParser.type = types[i];
        }
        catch(ex){};
    }
    throw new Error("No suitable XML parser installed for XMLHttp operations");
}

function XmlHttp(){}

XmlHttp.create = function () {
    try {
        if(window.XMLHttpRequest) {
            return new XMLHttpRequest();
        }
        if(window.ActiveXObject) {
            return new ActiveXObject(getXMLParser());
        }
    }
    catch(ex){};
    throw new Error("XMLHttp is not supported on this browser");
};


Even copy/paste uit mijn eigen code, maar daarna kun je wat met de xmlHttp factory doen

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
function loadXML(parentNode){
    
    var xmlHttp = XmlHttp.create();

    // prevent caching by browser, add &nocache if ? exists, else ?nocache
    var xmlUrl = parentNode.src 
    if(parentNode.src.indexOf('?') < 0){
        xmlUrl += '?nocache='+new Date().getTime();
    }else{
        xmlUrl += '&nocache='+new Date().getTime();
    }

    xmlHttp.open("GET", xmlUrl, true);
    xmlHttp.onreadystatechange = function () {
        if (xmlHttp.readyState == 4) {
            onXMLLoaded(xmlHttp,parentNode);
        }
    };
    
    //window.setTimeout(function () {
        xmlHttp.send(null);
    //}, 10);
}

function onXMLLoaded(oXML,parentNode) {
    
    var oXmlDoc = oXML.responseXML;
    var error;
    
    if(!oXmlDoc || oXmlDoc.parserError && oXmlDoc.parseError.errorCode != 0 || !oXmlDoc.documentElement){
        if (!oXmlDoc || oXmlDoc.parseError.errorCode == 0){
            error = {
                src : parentNode.src,
                status : oXML.status,
                statusText : oXML.statusText,
                type : 'undefined'
            }
        }else{
            error = {
                src : parentNode.src,
                reason : oXmlDoc.parseError.reason,
                srcText : oXmlDoc.parseError.srcText,
                errorCode : oXmlDoc.parseError.errorCode,
                type : 'parser'
            }
        }
        parentNode.error = error;
        parentNode.onError();
    }else{
        var root = oXmlDoc.documentElement;
        var cs = root.childNodes;
        var l = cs.length;
                    
        for (var i = 0; i < l; i++) {
            if (cs[i].tagName == "tree") {
                xmlNodeToJsNode(cs[i],parentNode);
            }
        }
        
        if(cs.length <= 0){
            // remove plus icons, this prevents overlapping of background dots forming a solid line
            parentNode.onloadedEmpty();
        }else{
            parentNode.onloaded();
        }
    }
    
    delete oXML.onreadystatechange;
    oXML.abort();
    oXML = null;
    delete oXML;
    
}

[ Voor 53% gewijzigd door Verwijderd op 08-04-2006 17:07 ]


  • Blaise
  • Registratie: Juni 2001
  • Niet online
Ik heb het opgelost door requests te queuen.

Ik weet niet of het een slimme methode is (ben geen xmlhttprequest pro), maar tot nu toe ben ik geen bugs tegen gekomen. In theorie zou het kunnen zijn dat een request mislukt en alle andere requests moeten wachten tot die ene request een timout geeft, maar dat ben ik nog niet tegen gekomen.

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// xml http
var xmlhttp
var bezig = false;

function getHTTP(el,url){
    if (!bezig){
        bezig = true;
        if (window.XMLHttpRequest){
            xmlhttp=new XMLHttpRequest()
            xmlhttp.onreadystatechange=stateChange
            xmlhttp.open("GET",url,true)
            xmlhttp.send(null)
        }
        else if (window.ActiveXObject){
            xmlhttp=new ActiveXObject("Microsoft.XMLHTTP")
            if (xmlhttp){
                xmlhttp.onreadystatechange=stateChange
                xmlhttp.open("GET",url,true)
                xmlhttp.send()
            }
        }
    }
    else{
        setTimeout('getHTTP("'+el+'","'+url+'")',100);
    }
}
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
function stateChange(){
    if (xmlhttp.readyState==4){
        bezig = false;
        if (xmlhttp.status==200){
            alert(xmlhttp.responseText);
        }
        else{
            alert("Error bij ophalen rating:" + xmlhttp.statusText)
        }
    }
}

Verwijderd

Afaik, is het enige nadeel van jouw implementatie dat er maar een enkele request wordt uitgevoerd, en je met losse objecten maximaal twee simultane requests per keer kunt uitvoeren op een browser als IE. Puur theoretisch zijn losse objecten dus de performante oplossing. Voor Gecko is de aanpak van losse objecten nog sneller omdat deze zich niet houdt aan de regels mbt simultane connecties. Voor kHTML en Opera weet ik niet wat daar het aantal simultane connecties voor zijn. :)

  • Scorpion1984
  • Registratie: Juni 2002
  • Laatst online: 13-02 12:30
Ik heb hem ondertussen zelf kunnen oplossen, het probleem in opera was dat de triggerfunctie nooit op level 4 kwam bij de 2e aanvraag. Als je bij elke request een nieuw xmlhttprequest object aanmaakt werkt mijn script wel. Als ik dit niet doe komt de status in opera om een of andere vage reden bij de tweede xmlhttprequest nooit op complete(4) te staan.

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 09-12-2025
Ik vind het nog steeds een vreemde oplossing. Heb je echt getest hoe de performance op de normale manier is? Zoals je het nu doet is het overigens niet geheel asynchroon meer, omdat de requests op elkaar wachten. Ik durf zelfs te beweren dat het geheel nu alleen nog maar meer tijd in beslag neemt, en dus nadelig voor de gebruiker is.

Noushka's Magnificent Dream | Unity


  • Scorpion1984
  • Registratie: Juni 2002
  • Laatst online: 13-02 12:30
Asynchroon wil zeggen dat de user-interface niet gaat hangen bij lange response tijden van de server. Verder valt de performance wel mee aangezien er over het algemeen niet heel veel requests tegelijk zullen plaatsvinden.

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 09-12-2025
Maar waarom dan, in vredesnaam :P, zo'n constructie en niet gewoon normaal requests uitvoeren?

Noushka's Magnificent Dream | Unity

Pagina: 1