Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Skripten / Logik
    4. JavaScript
    5. [Neu] Diverse async-Funktionen im JavaScript-Adapter

    NEWS

    • Neuer Blog: Fotos und Eindrücke aus Solingen

    • ioBroker@Smart Living Forum Solingen, 14.06. - Agenda added

    • ioBroker goes Matter ... Matter Adapter in Stable

    [Neu] Diverse async-Funktionen im JavaScript-Adapter

    This topic has been deleted. Only users with topic management privileges can see it.
    • paul53
      paul53 @Mic last edited by

      @Mic sagte:

      bei const obj = getObject(id); können wir nicht sicher sein, dass obj in der nächsten Zeile schon gesetzt ist

      getObject(id) arbeitet synchron, indem es auf den Puffer der Javascript-Instanz zugreift. Diese Version funktioniert natürlich nicht mit Haken bei "Nicht alle Zustände beim Start abonnieren".

      AlCalzone hanss 2 Replies Last reply Reply Quote 0
      • AlCalzone
        AlCalzone Developer @paul53 last edited by

        @paul53 Ja, das Beispiel von @Mic war nicht gut 😉 Dennoch ist es bei der Version mit xyzAsync egal, ob der Haken gesetzt ist oder nicht.

        1 Reply Last reply Reply Quote 1
        • hanss
          hanss @paul53 last edited by

          @paul53 sagte in [Neu] Diverse async-Funktionen im JavaScript-Adapter:

          getObject

          Bedeutet das, dass der js adapter zwangsläufig neu gestartet werden muß, wenn sich an den Aufzählungen etwas ändert?

          1 Reply Last reply Reply Quote 0
          • S
            stan23 last edited by stan23

            Hallo,
            die neuen Möglichkeiten durchdie async-Funktionen hören sich toll an.

            Nun versuche ich gerade meine alten Callback-Höllen aufzuräumen 🙂

            Gibt es einen asynchronen Ersatz für exec oder muss man das mit Promises bauen?

            function fetchCropPictureMbCam () {
                return new Promise((resolve) => {
                    cmd = `${wgetCmd} ${picturePathMbCam} ${mailboxCamURL}`;
                    exec(cmd, async function (error, stdout, stderr) {
                        log(`Exec: ${cmd}`);
                        log(`Exec: stdout: ${stdout}, stderr: ${stderr}, error: ${error}`);
                        cmd = `${imageMagickCmd} ${picturePathMbCam} ${imageMagickParams} ${picturePathMbCamCropped}`;
                        exec(cmd, async function (error, stdout, stderr) {
                            log(`Exec: ${cmd}`);
                            log(`Exec: stdout: ${stdout}, stderr: ${stderr}, error: ${error}`);
                            resolve();
                        });
                    });
                });
            }
            
            
            subscribe({id: dpMailboxFlap, change: "ne", val: 'open'}, async function(obj) {
                log('Mailbox: Flap has been opened');
            
                setState(dpMailboxFillState, eMailboxFillState.filled, true);
                /* wait 5 seconds so that letters can be thrown in */
                await wait(5000);
                await fetchCropPictureMbCam();
                sendTo('pushover.0', 'send',  {
                    title: 'Briefkasten',
                    message: "Es wurde Post eingeworfen.",
                    file: picturePathMbCamCropped,
                });
            });
            
            

            EDIT:
            ist das so richtig? das resolve() kommt an die Stelle wenn die Callbacks fertig sind?

            AlCalzone 1 Reply Last reply Reply Quote 0
            • AlCalzone
              AlCalzone Developer @stan23 last edited by

              @stan23 Für exec gibts tatsächlich keinen Ersatz, weil das Rückgabeobjekt nicht ganz eindeutig wäre.
              Dein Code ist so fast korrekt:

              • async vor den functions in fetchCropPictureMbCam ist unnötig, da du darin kein await verwendest
              • cmd wird nirgends deklariert.
              S N 2 Replies Last reply Reply Quote 0
              • S
                stan23 @AlCalzone last edited by

                @AlCalzone said in [Neu] Diverse async-Funktionen im JavaScript-Adapter:

                Dein Code ist so fast korrekt:

                • async vor den functions in fetchCropPictureMbCam ist unnötig, da du darin kein await verwendest
                • cmd wird nirgends deklariert.

                Stimmt, das Erste ist ein Relikt aus meinen Versuchen, das Zweite war noch global deklariert.
                Habe ich beides geändert und funktioniert.
                Vielen Dank!

                Gibt es denn beim setState auch etwas zu beachten?
                Ich hatte mir vor langer Zeit mal gemerkt dass man für HomeMatic die Einschaltdauer und den tatsächlichen Schaltbefehl so setzen soll:

                setState("hm-rpc.2.NEQ0115240.1.ON_TIME", 2*3600, function() {
                    setState("hm-rpc.2.NEQ0115240.1.STATE", true);
                });
                

                Ist das noch okay oder gibt es da auch eine komfortablere Variante? Oder einfach 2 setState hintereinander weil die sich nicht überholen können?

                AlCalzone 1 Reply Last reply Reply Quote 0
                • AlCalzone
                  AlCalzone Developer @stan23 last edited by

                  @stan23 sagte in [Neu] Diverse async-Funktionen im JavaScript-Adapter:

                  Oder einfach 2 setState hintereinander weil die sich nicht überholen können?

                  Eine "komfortablere" Variante für zwei getrennte States gibt es nicht. Mit await setStateAsync(...) kannst du sie aber einfach unterenander hängen, weil die sich nicht überholen (im Gegensatz zu setState, wo du einen callback brauchst)

                  S 1 Reply Last reply Reply Quote 1
                  • S
                    stan23 @AlCalzone last edited by

                    @AlCalzone das finde ich komfortabel genug 🙂

                    1 Reply Last reply Reply Quote 0
                    • N
                      noox @AlCalzone last edited by

                      @AlCalzone
                      Gibt es auch eine Lösung für einen async HTTP-Request? Oder soll man es am besten noch ähnlich wie das stan23 für exec gemacht hat lösen?

                      Ich vermute mal, dass die request-Funktion von ioBroker auf das Node-Modul "request" aufbaut? Stimmt das? Das ist scheinbar auch seit Februar "deprecated": https://www.npmjs.com/package/request

                      N AlCalzone 2 Replies Last reply Reply Quote 0
                      • N
                        Nahasapee @noox last edited by

                        @noox hi ich hab das thema bei mir so gelöst:

                        https://github.com/Nahasapeemapetilon/MyTelegramMenu/blob/f2effab433a419e7f04967c319dd636f7a08e4cc/lib/googlepolling.js#L91

                        und hier der wait

                        https://github.com/Nahasapeemapetilon/MyTelegramMenu/blob/f2effab433a419e7f04967c319dd636f7a08e4cc/lib/googlepolling.js#L110

                        viele grüße

                        1 Reply Last reply Reply Quote 1
                        • AlCalzone
                          AlCalzone Developer @noox last edited by

                          @noox sagte in [Neu] Diverse async-Funktionen im JavaScript-Adapter:

                          Gibt es auch eine Lösung für einen async HTTP-Request?

                          Entweder so wie mein Vorposter.
                          Alternativ ginge z.b. die u.a. von mir bevorzugte Library https://github.com/axios/axios - die Beispiele dort sind mit Promises und .then geschrieben, lassen sich aber selbstverständlich auch mit await nutzen

                          N P 2 Replies Last reply Reply Quote 1
                          • N
                            noox @AlCalzone last edited by

                            @Nahasapee, @AlCalzone Vielen Dank!
                            Mit Axios geht das echt easy.

                            Erster Versuch für simples Get mit JSON-Response in Typescript:

                            const axios = require('axios').default;
                            
                            class ... { 
                            
                                public static async httpGetRequestJson(url: string, throwException: boolean = false): Promise<any> {
                                    let response: any;
                                    try {
                                        response = await axios.get(url, {
                                            timeout: 10000,
                                        });
                                    } catch(exception) {
                                        log(`error fetching url ${url}: ${JSON.stringify(exception)}`, 'error');
                                        if(throwException) throw exception;
                                        return undefined;
                                    }
                                    if(response.status != 200) {
                                        log(`error fetching url ${url}. Status: ${response.status} ${response.statusText}. Response: ${JSON.stringify(response)}`, 'error');
                                        if(throwException) throw new Error(`Response status: ${response.status} ${response.statusText}.`);
                                        return undefined;            
                                    }
                                    // log(response.data);
                                    return response.data;
                                }
                            
                            }
                            

                            Hier wurde das Thema eh auch schon aufgegriffen - hatte es aber erst jetzt (wegen dem Hinweis auf Axios) gefunden: https://forum.iobroker.net/topic/36039/alternative-für-request-paket

                            PS: Wer sich den response komplett ansehen möchte: Bei wir waren da zirkuläre Referencen drinnen, sodass JSON.stringify nicht funktionierte. Auf Stackoverflow gibt's ein paar Diskussionen dazu. Ein Workaround z.B. hier: https://stackoverflow.com/a/48845206

                            1 Reply Last reply Reply Quote 0
                            • P
                              Pittini Developer @AlCalzone last edited by

                              @AlCalzone sagte in [Neu] Diverse async-Funktionen im JavaScript-Adapter:

                              @noox sagte in [Neu] Diverse async-Funktionen im JavaScript-Adapter:

                              Gibt es auch eine Lösung für einen async HTTP-Request?

                              Entweder so wie mein Vorposter.
                              Alternativ ginge z.b. die u.a. von mir bevorzugte Library https://github.com/axios/axios - die Beispiele dort sind mit Promises und .then geschrieben, lassen sich aber selbstverständlich auch mit await nutzen

                              Ich stell mich leider mal wieder zu doof an, ich hab das Beispiel von Axios versucht umzusetzen, aber da kommt immer nurn leeres Objekt. Hat da evtl jemand nen Beispiel was läuft? Oder kann mir sagen was da verkehrt ist (ich und Objekte werden einfach keine Freunde mehr)?

                              const axios = require('axios');
                              
                              getData();
                              async function getData() {
                                try {
                                  const response = await axios.get('https://miot-spec.org/miot-spec-v2/instance?type=urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-ma4:1',{timeout : 10000});
                                  console.log("resp:"+JSON.stringify( response));
                                } catch (error) {
                                  console.error(error);
                                }
                              }
                              
                              N F 2 Replies Last reply Reply Quote 0
                              • N
                                noox @Pittini last edited by noox

                                @Pittini
                                JSON.stringify funktioniert eventuell nicht auf response, weil hier zirkuläre Referenzen drinnen sind. Siehe meinen Stackoverflow-Link von oben. Aber der Fehler müsste dann im catch() geloggt werden.

                                Probier mal z.B. nur response.status, response.data, etc.

                                1 Reply Last reply Reply Quote 0
                                • zaunermax
                                  zaunermax last edited by

                                  Mega nice, ich werde gleich alle meine synchronen calls auswechseln. Ich hab sogar vorher einen primitiven Promise wrapper gehabt, aber nativ das ganze zu haben ist sehr geil 🙌

                                  1 Reply Last reply Reply Quote 0
                                  • F
                                    fastfoot @Pittini last edited by

                                    @Pittini sagte in [Neu] Diverse async-Funktionen im JavaScript-Adapter:

                                    Ich stell mich leider mal wieder zu doof an, ich hab das Beispiel von Axios versucht umzusetzen, aber da kommt immer nurn leeres Objekt. Hat da evtl jemand nen Beispiel was läuft? Oder kann mir sagen was da verkehrt ist (ich und Objekte werden einfach keine Freunde mehr)?

                                    wie schön, wenn man mal nicht der einzige 'Doofe' ist 🙂 Dein Beispiel läuft bereits perfekt, wenn du JSON.stringify(response.data) nimmst. Das was sonst noch so drin steht findest du mit Object.keys(response) raus, welche du dann alle mit JSON.stringify() untersuchen kannst

                                    P 1 Reply Last reply Reply Quote 2
                                    • P
                                      Pittini Developer @fastfoot last edited by

                                      @fastfoot sagte in [Neu] Diverse async-Funktionen im JavaScript-Adapter:

                                      wie schön, wenn man mal nicht der einzige 'Doofe' ist Dein Beispiel läuft bereits perfekt, wenn du JSON.stringify(response.data) nimmst. Das was sonst noch so drin steht findest du mit Object.keys(response) raus, welche du dann alle mit JSON.stringify() untersuchen kannst

                                      Wow, so einfach. Danke! Ich geh jetzt in die Ecke schämen.

                                      N 1 Reply Last reply Reply Quote 0
                                      • N
                                        noox @Pittini last edited by noox

                                        Ich hatte zuletzt wiederholt Restarts vom Javascript-Adapter.
                                        Es dürfte auftreten, wenn ich setStateAsync oder getStateAsync verwende, aber zuvor vergessen habe, den State überhaupt anzulegen.

                                        Hier in dem Fall hatte ich den Prefix bei meinem State vergessen. Es kamen dann folgende Log-Einträge:

                                        host.smarthome	2020-12-19 00:28:58.620	info	Restart adapter system.adapter.javascript.0 because enabled
                                        host.smarthome	2020-12-19 00:28:58.619	error	instance system.adapter.javascript.0 terminated with code 6 (UNCAUGHT_EXCEPTION)
                                        host.smarthome	2020-12-19 00:28:58.619	error	Caught by controller[0]: State "FullyKioskErreichbar" not found
                                        host.smarthome	2020-12-19 00:28:58.613	error	Caught by controller[0]: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected
                                        javascript.0	2020-12-19 00:28:58.187	info	(9941) terminating
                                        javascript.0	2020-12-19 00:28:58.186	info	(9941) terminating
                                        javascript.0	2020-12-19 00:28:57.981	warn	(9941) Terminated (UNCAUGHT_EXCEPTION): Without reason
                                        

                                        Ein try { ... } catch(error) { } hilft, aber wenn man das nicht hat ist ein Restart ja doch eher problematisch, oder?

                                        PS: Hab extra noch upgedatet:
                                        Node: 12.20.0
                                        JS-Adapter: 4.10.8 (also latest)
                                        JS-Controller: 3.1.6

                                        Nachtrag: Auf Github habe ich dazu noch nix gefunden.

                                        N 1 Reply Last reply Reply Quote 0
                                        • N
                                          noox @noox last edited by noox

                                          Update: Ich dürfte einen Fehler gemacht haben. Das Beispiel von unten ist zu einfach. Da dürfte es zu keinem Problem kommen. Aber Prinzipiell gibt es das Problem.

                                          Ist eigentlich jemand von euch schon auf "Concurrency"-Probleme gestoßen? JavaScript ist ja Singlethreaded, sodass man sich normalerweise nicht um Concurrency kümmern muss.

                                          Aber mit async/await kann es leicht passieren, dass derselbe Code scheinbar "gleichzeitig" ausgeführt wird.

                                          Aktuelles Beispiel:
                                          Ich hole mir mit einem HTTP-Request einige Status-Werte eines Gerätes. Ich hab das etwas abstrahiert und gecached. D.h. ich sage sowas wie: getValue('X'). Wenn der Werte vom letzten Abruf noch nicht zu alt ist, liefert mir getValue den direkt, sonst werden die Werte zuvor per HTTP-Request neu geladen.

                                          let x = await getValue(`X`);
                                          let y = await getValue(`Y`);
                                          

                                          Schaut unscheinbar aus 😉
                                          Aber wenn der Cache nicht mehr gültig ist, dann werden hier zwei HTTP-Requests gemacht. Während nämlich getValue('X') auf den HTTP-Response wartet, wird getValue('Y') ausgeführt und startet dann ebenfalls den HTTP-Request.

                                          Das Ganze würde natürlich mit Callbacks genauso passieren.

                                          Etwas Änliches kann auch mit set/getStateAsync passieren. Auch beim "alten" setState. Da aber das "alte" getState blockiert, stolpert man da nicht so häufig drüber.

                                          Leider hat JavaScript zwar async/await aber - soweit ich weiß - keinen eingebauten Locking-Mechanismus (Locks, Semaphore oder Ähnliches.)

                                          Es gibt ein paar NPM-Module. Hat da schon jemand Erfahrung, was da sinnvoll ist?

                                          AlCalzone 1 Reply Last reply Reply Quote 0
                                          • AlCalzone
                                            AlCalzone Developer @noox last edited by

                                            @noox sagte in [Neu] Diverse async-Funktionen im JavaScript-Adapter:

                                            Während nämlich getValue('X') auf den HTTP-Response wartet, wird getValue('Y') ausgeführt und startet dann ebenfalls den HTTP-Request.

                                            Genau das verhindert await eigentlich (wenn die Funktion entweder async ist oder einen Promise zurück gibt). Ich gehe schwer davon aus, dass deine getValue-Funktion nicht richtig implementiert ist.

                                            @noox sagte in [Neu] Diverse async-Funktionen im JavaScript-Adapter:

                                            Etwas Änliches kann auch mit set/getStateAsync passieren.

                                            Eigentlich nicht. Zeig doch bitte mal ein Beispiel, wo das nachvollziehbar ist.

                                            N 1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post

                                            Support us

                                            ioBroker
                                            Community Adapters
                                            Donate

                                            959
                                            Online

                                            31.8k
                                            Users

                                            80.0k
                                            Topics

                                            1.3m
                                            Posts

                                            javascript
                                            12
                                            39
                                            6319
                                            Loading More Posts
                                            • Oldest to Newest
                                            • Newest to Oldest
                                            • Most Votes
                                            Reply
                                            • Reply as topic
                                            Log in to reply
                                            Community
                                            Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
                                            The ioBroker Community 2014-2023
                                            logo