NEWS
Gültigkeitsbereich Variablen
-
Hallo allerseits,
ich habe ein grundsätzliches Verständnisproblem beim Gültigkeitsbereich von Variablen. Auch nach stundenlangem Lesen unzähliger Tutorials bin ich offenbar zu blöd...
Vielleicht kann mir ja jemand etwas "Starthilfe" anhand eines konkreten Beispiels (Bsp. vereinfacht für bessere Lesbarkeit) geben:
let aussenTemp = 'hm-rpc.0.NEQ1382028.1.TEMPERATURE'; function lesenTemp(tempID){ let tempMax = -100; log("initial: " + tempMax); let end = new Date(); end.setHours(23,59,59,999); end.setDate(end.getDate() - 1 ); // gestern let start = new Date(end); start.setHours(0,0,0,0); sendTo('sql.0', 'getHistory', { id: tempID, options: { start: start, end: end, aggregate: 'none', addId: true } }, function (result) { if (!result.error){ tempMax = result.result[0].val; log("innere function: " + tempMax); } } ); log("aussen: " + tempMax); } lesenTemp(aussenTemp);
Das Beispiel erzeugt folgende Ausgabe:
19:40:47.421 info javascript.0 (17473) script.js.common.test.sqlTest: initial: -100 19:40:47.422 info javascript.0 (17473) script.js.common.test.sqlTest: aussen: -100 19:40:47.429 info javascript.0 (17473) script.js.common.test.sqlTest: innere function: 6
Wie kann ich in dem Beispiel den Rückgabewert der SQL-Abfrage nach "außen" weitergeben? Wenn ich z.B. mit dem Ergebnis mehrerer Abfragen weiterarbeiten möchte und nicht nur dieses eine Ergebnis innerhalb der Rückgabe function benötige...
Ein "return" bringt auch keinen Erfolg, da er ja nicht in die function "lesenTemp" zurückspringt, sondern... ...tja, wohin genau?
Schonmal vielen Dank, falls es jemand schafft, das auch mir verständlich zu erklären...
-
@spider_01 sagte in Gültigkeitsbereich Variablen:
Wie kann ich in dem Beispiel den Rückgabewert der SQL-Abfrage nach "außen" weitergeben?
Das Problem ist, dass dein Callback (welcher ja auch nur als Parameter an "sendTo" übergeben wird, erst nach dem Log ausgeführt wird. Einfacher wäre es, auf die Ausführung zu warten und mit Promises zu arbeiten (also der Async-Variante).
Den Code musst Du so lesen: "Hier ist die Aufgabe, wenn Du fertig bist, ruf bitte diese Funktion auf, ich mache aber schonmal weiter." Deswegen ja auch der Callback. Würde die Logik synchron ausgeführt, könnte man ja mit einem einfachen Rückgabewert arbeiten.
-
So z.B. (kein Anspruch auf Vollständigkeit, nur kurz um Forum getippt)
const aussenTemp = 'hm-rpc.0.NEQ1382028.1.TEMPERATURE'; async function lesenTemp(tempID) { let tempMax = -100; log('initial: ' + tempMax); const end = new Date(); end.setHours(23, 59, 59, 999); end.setDate(end.getDate() - 1); // gestern const start = new Date(end); start.setHours(0, 0, 0, 0); try { const result = await sendToAsync('sql.0', 'getHistory', { id: tempID, options: { start: start, end: end, aggregate: 'none', addId: true } }); tempMax = result.result[0].val; log('aussen: ' + tempMax); } catch (err) { console.error(err); } } lesenTemp(aussenTemp);
Stichworte für Google sind:
- Async/Await
- JavaScript Promises
- Promise vs. Callback
-
@haus-automatisierung: Herzlichen Dank für die schnelle Rückmeldung!!!
So z.B. (kein Anspruch auf Vollständigkeit, nur kurz um Forum getippt)
Kein Problem, bin für jede Hilfe dankbar!
Stichworte für Google sind:
- Async/Await
- JavaScript Promises
- Promise vs. Callback
Oha, daran bin ich auf meiner Recherche auch schon vorbeigekommen. Bisher mit mäßigem Erfolg, was mein Verständnis betrifft...
Aber hilft ja nix, muss da wohl doch noch viiiel mehr Zeit investieren.
Werde erstmal versuchen, Dein Bsp. nachzuvollziehen. Nochmal Danke!
-
@spider_01 sagte in Gültigkeitsbereich Variablen:
Bisher mit mäßigem Erfolg, was mein Verständnis betrifft...
Kann verwirrend sein, ist aber eigentlich ganz einfach. Mach Dir ein paar Beispiele mit
setTimeout
und Promises. Dann wird das schnell klar. Also ganz unabhängig vom ioBroker - reines JavaScript.function start() { setTimeout(() => { console.log('jetzt'); }, 1000); } start(); console.log('ende');
Da wird ja auch eine Funktion als Callback übergeben, aber der Code wird weiter ausgeführt. Es wird also erst
ende
ausgegeben und eine Sekunde späterjetzt
.Wenn Du darauf warten möchtest, musst Du ein Promise zurückgeben.
function start() { return new Promise(resolve => { setTimeout(() => { console.log('jetzt'); resolve(); }, 1000); }); } start(); console.log('ende');
Davon hast Du erstmal nix gewonnen, aber Du kannst eben mit dem Promise weiter machen:
function start() { return new Promise(resolve => { setTimeout(() => { console.log('jetzt'); resolve(); }, 1000); }); } start() .then(() => { console.log('ende'); });
.then()
wird ausgeführt, wenn das Promise erfüllt wird. Alsoresolve
aufgerufen wird. Dann kannst Du weiter machen. Natürlich könntest Du auch Daten übergeben:function start() { return new Promise(resolve => { setTimeout(() => { resolve('jetzt'); }, 1000); }); } start() .then((ergebnis) => { console.log(ergebnis); console.log('ende'); });
Und async/await ist einfach nur eine andere Schreibweise, damit man das nicht mit
.then
schachteln muss.async function start() { return new Promise(resolve => { setTimeout(() => { resolve('jetzt'); }, 1000); }); } async function wrapper() { const ergebnis = await start(); console.log(ergebnis); console.log('ende'); } wrapper();
Etwas schwierig zu verstehen ist nun eventuell, dass man
await
nicht auf der "obersten" Ebene im Code verwenden kann (geht im ioBroker schon, aber dann beschwert sich ggf. die IDE). Immer wenn Duawait
verwendest, musst die umliegende Funktion mitasync
gekennzeichnet sein.Schau auch noch try/catch vs
.error()
an (zusammen mitreject
). -
Hab's mal versucht (sträflicherweise ohne try/catch), und hänge an zwei Punkten:
const aussenTemp = 'hm-rpc.0.NEQ1382028.1.TEMPERATURE'; async function lesenTemp(tempID){ let tempMax = -100; log("initial: " + tempMax); const end = new Date(); end.setHours(23,59,59,999); end.setDate(end.getDate() - 1 ); // gestern const start = new Date(end); start.setHours(0,0,0,0); const result = await sendTo('sql.0', 'getHistory', { id: tempID, options: { start: start, end: end, aggregate: 'none', addId: true } }); log (result); // log("aussen: " + tempMax); } lesenTemp(aussenTemp);
Zum einen scheint
const result = await sendTo('sql.0', 'getHistory', {
nicht so zu funktionieren, wie ich das erwartet hätte, denn die Ausgabe lautet
21:38:15.535 info javascript.0 (17473) Stop script script.js.common.test.sqlTest 21:38:15.585 info javascript.0 (17473) Start javascript script.js.common.test.sqlTest 21:38:15.591 info javascript.0 (17473) script.js.common.test.sqlTest: initial: -100 21:38:15.592 info javascript.0 (17473) script.js.common.test.sqlTest: undefined
Zum anderen sagt zumindest der Editor als Mousover zum unterkringelten "await" vor "sendTo": 'await' has no effect on the type of this expression. (80007)
-
Oh, da warst du wesentlich schneller mit Input, als ich mit dem Ausprobieren! Werde mich mal eingehender damit beschäftigen (müssen)!
Vielen Dank für den Input!
-
@spider_01 Du musst sendToAsync nutzen. Nicht mehr sendTo. Nur die erste liefert ein Promise zurück. sendTo arbeitet ja mit Callback.