Javascript ist zu schnell

OP #4267821
Lesenswert?

Hallo an alle,

ich habe ein kleines Problem mit meinem Javascript...
1
function startTest() {
2
  "use strict";
3
  var request = false,
4
    i = 0,
5
    timeToWait = 0;
6
  
7
  function frequencyComplete() {
8
        if (request.readyState === 4) {
9
            if (request.status === 200) {
10
        var data = JSON.parse(request.responseText);
11
        
12
        timeToWait = data.DelayTime;
13
            }
14
        }
15
    }
16
  
17
  request = new XMLHttpRequest();
18
  if (request) {
19
    request.open("GET", "/getfrequency?id=" + Math.random(), true);
20
    request.onreadystatechange = frequencyComplete;
21
    request.send(null);
22
  }
23
  
24
  function testComplete() {
25
        if (request.readyState === 4) {
26
            if (request.status === 200) {
27
        var data = JSON.parse(request.responseText);
28
        
29
        changeDosingPointColor(i, data.Auswertung);
30
            }
31
        }
32
    }
33
  
34
  for (i = 0; i < 50; i += 1) {
35
    request = false;
36
    request = new XMLHttpRequest();
37
    if (request) {
38
      request.open("GET", "/starttest?id=" + Math.random(), true);
39
      request.onreadystatechange = testComplete;
40
      request.send(null);
41
    }
42
    setTimeout(timeToWait);
43
  }
44
  
45
  getTestTableValues();
46
}

Mit dieses Funktion möchte ich 50 mal einen Vorgang auf einem Arrduino 
auslösen. Der wertet dann eine bestimmte Zeit einen analogen Eingang aus 
und schickt dann ein "Gut" (1) oder ein "Schlecht" (0) zurück. Mit 
diesem Ergebnis sollen dann Punkte grün oder rot gefärbt werden.

Ich habe aber die Vermutung, dass das Script zu schnell ist. Wenn ich 
das so ausführe wird gar nichts gefärbt aber wenn ich das z.B. mit 
Firefox debugge dann werden die Kreise gefärbt.

Ich habe schon versucht mir die Frequenz (max. 20 Hz) vom Arduino vorher 
zu holen und damit dann ein setTimeout zu machen aber das hilft auch 
irgendwie nicht. In "timeToWait" steht dann gerne mal nichts drin, also 
eine 0.

Ich hoffe hier ist jemand der mir dabei helfen kann das Problem zu 
lösen.

MfG Kilian
Gast #4267847
Lesenswert?

setTimeout() erwartet doch eigentlich eine JS-Funktion und die Wartezeit 
in ms als Parameter? Du scheinst es hier als ne Art Sleep() nutzen zu 
wollen  - Das wird so vermutlich gar keinen Effekt haben?

Außerdem läuft deine for-Schleife bereits, wenn die Antwort von 
getfrequency noch gar nicht angekommen sein dürfte und timeToWait wird 
zunächst dann den Standardwert 0 haben.

request.send() arbeitet nicht synchron! D.h. der nachfolgende JS-Code 
läuft direkt weiter und die frequencyComplete-Funktion wird erst 
"mittendrin" aufgerufen, sobald die Antwort vom Server da ist.
#4267906
Lesenswert?

Falls du nicht wirklich alles Löw-Level machen willst, Les dich mal hier 
ein:
http://www.w3schools.com/jquery/jquery_ajax_intro.asp
Da sind viele der JS-Gemeinheiten versteckt.

Hier schon mal was zum durchknobeln:
1
<!DOCTYPE html>
2
<html>
3
<head>
4
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
5
<script>
6
$(document).ready(function(){
7
    $("button").click(function(){
8
        $("#div1").load("demo_test.txt", function(responseTxt, statusTxt, xhr){
9
            if(statusTxt == "success")
10
                alert("External content loaded successfully!");
11
            if(statusTxt == "error")
12
                alert("Error: " + xhr.status + ": " + xhr.statusText);
13
        });
14
    });
15
});
16
</script>
17
</head>
18
<body>
19

20
<div id="div1"><h2>Let jQuery AJAX Change This Text</h2></div>
21

22
<button>Get External Content</button>
23

24
</body>
25
</html>
Wichtig für's Verständnis: $() selektiert Element aus deiner Seite. 
"#div1" z.B. das Element mit der Id "div1" (Achtung Id und Name eines 
Elements sind Unterschiedliche Dinge).
Zu deinem Problem: AJAX ist asynchron (sonst würde es SJAX gennant 
werden), d.h. der Arduino darf sich mit der Antwort auf getfrequency 
ruhig Zeit lassen und dann Antworten. Innerhalb des gleichen 
TCP-/http-/... Requests. Ich gehe mal davon aus, daß auf dem Arduino ein 
rudimentärer http-Server läuft. Wenn nicht, dann hat JS im Browser eh 
wenig Chancen.
OP #4267922
Lesenswert?

Erstmal danke für eure Antworten!

Carl D. schrieb:
> Ich gehe mal davon aus, daß auf dem Arduino ein
> rudimentärer http-Server läuft. Wenn nicht, dann hat JS im Browser eh
> wenig Chancen.

Jap auf dem Arduino läuft der lwIP Stack mit einem Webserver.

Da ich aber leider noch nicht so in Javascript bewandert bin, fällt mir 
so jetzt nicht wirklich eine Lösung ein :/ Wie könnte ich das denn 
umschreiben damit z.B. alles nach einer Antwort vom Arduino weiter 
abgearbeitet wird?
OP #4267962
Lesenswert?

Habe es glaub ich hinbekommen!
1
function startTest() {
2
  "use strict";
3
  var request = false,
4
    i = 0,
5
    s = 0,
6
    timeToWait = 0,
7
    data = 0;
8
  
9

10
  function sleep(milliseconds) {
11
    var start = new Date().getTime();
12
    for (s = 0; s < 1e7; s += 1) {
13
      if ((new Date().getTime() - start) > milliseconds) {
14
        break;
15
      }
16
    }
17
  }
18

19
  request = new XMLHttpRequest();
20
  if (request) {
21
    request.open("GET", "/getfrequency?id=" + Math.random(), false);
22
    request.send(null);
23
  }
24
  
25
  if (request.readyState === 4) {
26
    if (request.status === 200) {
27
      data = JSON.parse(request.responseText);
28
      timeToWait = data.DelayTime;
29
    }
30
  }
31
  
32
  for (i = 0; i < 50; i += 1) {
33
    request = false;
34
    request = new XMLHttpRequest();
35
    if (request) {
36
      request.open("GET", "/starttest?id=" + Math.random(), false);
37
      request.send(null);
38
    }
39
    
40
    if (request.readyState === 4) {
41
      if (request.status === 200) {
42
        data = JSON.parse(request.responseText);
43
        
44
        changeDosingPointColor(i, data.Auswertung);
45
      }
46
    }
47
    sleep(timeToWait);
48
  }
49
  
50
  getTestTableValues();
51
}

Ich habe aus dem asynchrone einen synchrone request gemacht und meine 
eigene sleep Funktion geschrieben.
#4268243
Lesenswert?

Wenn du aber ernsthaft was mit Web-Oberflächen machen willst, dann 
solltest du dich in das "asynchrone" Konzept von JS/WebBrowser 
einarbeiten. Probier mal den Code aus dem jquery Tutorial (siehe oben) 
aus. Ersetze in der Zeile:
$("#div1").load("demo_test.txt", function(responseTxt, statusTxt, xhr){
die URL "demo_test.txt" durch deine "/getfrequency/id=...", dann sollte 
bei Knopfdruck das JSON-Ergebnis auf dem Browser auftauchen.
Mit deinem sleep machst du die ganze Browser-UI kaput, nennt sich auch 
"busy wait" und krallt sich einen CPU-Core.
Gast #4268567
Lesenswert?

Kilian K. schrieb:
> meine eigene sleep Funktion geschrieben.

Das ist aber nicht der richtige Ansatz. Besser ist so lange warten mit 
dem senden des nächsten Requests bis die Antwort vom vorherigen Request 
eingetroffen ist.
1
function startTest() {
2
    "use strict";
3
    var request = false,
4
        i = 0,
5
        timeToWait = 0;
6

7
        
8
    function sendRequest(url, callback) {
9
        request = new XMLHttpRequest();
10
        if (request) {
11
            request.open("GET", url + "?id=" + Math.random(), true);
12
            request.onreadystatechange = callback;
13
            request.send(null);
14
        }
15
    }
16

17
    function testComplete() {
18
        if (request.readyState === 4) {
19
            if (request.status === 200) {
20
                var data = JSON.parse(request.responseText);
21

22
                changeDosingPointColor(i, data.Auswertung);
23
                
24
                i ++;
25
                if(i < 50) {
26
                    /* noch nicht alle tests durch? Dann nächster Test */
27
                    sendRequest("startTest", testComplete);
28
                }
29
            }
30
        }
31
    }
32
    
33
    function frequencyComplete() {
34
        if (request.readyState === 4) {
35
            if (request.status === 200) {
36
                var data = JSON.parse(request.responseText);
37

38
                /* TUE WAS MIT DATA */
39
                
40
                sendRequest("startTest", testComplete)
41
            }
42
        }
43
    }
44

45
    sendRequest("getfrequency", frequencyComplete);
46
    getTestTableValues();
47
}
Gast #4268649
Lesenswert?

ah... Fehler entdeckt: getTestTableValues() soll natürlich im else-Zweig 
der if(i < 50) Abfrage stehen, nicht einfach am Ende der startTest() 
Funktion.
1
                if(i < 50) {
2
                    /* noch nicht alle tests durch? Dann nächster Test */
3
                    sendRequest("startTest", testComplete);
4
                } else {
5
                    /* sonst fertig ... */
6
                    getTestTableValues();
7
                }
8
...
9
    sendRequest("getfrequency", frequencyComplete);
10
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren