Umstieg von synchronen auf asynchronen Code / Ideen und Gedanken gesucht

  • Umstieg von synchronen auf asynchronen Code / Ideen und Gedanken gesucht

    Hallo zusammen,

    ich denke, mein Anliegen wird sicherlich dem einem oder anderen Entwickler genauso auf der Seele brennen wie mir bzw. er wird in der gleichen Situation. Ich entwickle seit vielen Jahren Software in PHP, gelegentlich in VB.NET und auch in JavaScript bzw. irgendwann dann mal mit Unterstützung von jQuery. Sicherlich gab es dann auch vor langerer Zeit mal den Punkt, wo ich gemerkt habe das es keine Lösung ist, AJAX-Aufrufe synchron auszuführen weil man damit konsequent den Browser blockier und habe entsprechend gelernt, saubere nachvollziehbare Lösungen mit asynchronen Aufrufen umzusetzen.

    Jetzt brennt mir es seit längere Zeit unter den Nägeln, mich mit Node.JS zu beschäftigen und ich habe jetzt auch im privaten Umfeld ein kleines Projekt für mich gefunden, was gut im Zusammenhang mit meiner Heimautomatisierung zusammenpasst.

    Es gibt eine Python Bibliothek (github.com/mjg59/python-broadlink), welche es erlaubt IR-Sender und Empfänger der Firma Broadlink anzusteuern und ich würde das gerne auf Node.JS portieren zusammen dann mit ExpressJS, um einen Server zur Verfügung zu stellen der via API-Aufrufen die Geräte steuern kann.

    Ganz grob hat die Bibliothek folgenden synchronen Ablauf mit dem ich zB ein Gerät ansprechen kann:
    1. Schicke einen UDP Broadcast ins Netzwerk
    2. Schreibe alle innerhalb einer Zeitspanne gefundene Geräte in ein Array mit deren Daten (MAC Adresse usw.)
    3. Nehme ein Gerät davon und authentifiziere dich
    4. Versetzte das Gerät in einen Lernmodus
    5. Gibt nach einer gewissen Zeitspanne (Timeout) das zurück, was für IR gesendet wurde
    Soweit, so gut, habe ich grundlegend das Protokoll aus der Python Bibliothek bereits rüber portiert (nicht vollständig, aber soweit das ich weiß dass es geht und ich weiß was noch gemacht werden muss), funktioniert auch super an sich. Jetzt kommt aber z.B. das "Problem":

    Ich muss zuerst einen Broadcast machen, dann muss ich jedes gefundene Gerät authentifizieren bevor ich in der Lage bin, an dieses eigens Kommandos senden zu können. Jetzt ist es ja aber so, dass ich erst ein Message-Event setzen muss und dann die Nachricht sende, bevor das Listener-Event reagiert und ich mir meine Daten rausziehen kann. In der synchronen Verarbeitung hätte ich die Daten verarbeitet, via Return zurückgegeben was dann in eine Variable gekippt worden wäre und dann hätte ich damit weiter gearbeitet. Wenn ich das aber richtig verstanden habe, läuft das hier nicht so.
    Wenn ich jetzt eine Idee weiter denke, sprich ich bin beim API-Server, fehlt mir die Idee, wie das hier konkret umgesetzt wird in Node.JS. Prinzipiell rufe ich z.B. dann über die API erst mal auf "Suche mir alle Geräte im Netzwerk", sollte darauf eine Rückmeldung erhalten. Dann picke ich mir ein Gerät raus, sage "Authentifiziere das Gerät" worauf hin ich ein "OK, hat geklappt" oder ein "Sorry, ging was schief" kommen sollte. Dann schicke ich z.B. ein "Geh in den Lernmodus" und z.B. nach 5 Sekunden kommt dann die Rückmeldung "Da, das wurde in der Zeit gesendet".
    Beim API-Aufruf stelle ich mir das jeweils als Longpoll vor, sprich ich warte bis eine Rückmeldung bzw. Timeout kommt. Wie nah oder fern bin ich den hier mit meinen Gedanken beim "Best practice"?

    Kennt ihr vielleicht vergleichbare Bibliotheken, die es auf sinnvolle Art und Weise implementieren wie ich es auch tun sollte, die ich als Beispiel / Orientierung nutzen kann?

    Ich hab anbei mal meinen aktuellen Stand angehängt - ist aktuell weder aufgeräumt noch groß kommentiert, vielleicht bekommt aber der eine oder andere eine Idee was ich meine und wo meine Reise hingehen sollte.

    Freue mich über jeden konstruktiven Beitrag, Inspirationen und Unterstützung! :)

    prodigy7
    Dateien
  • Hi,

    Mein Linter spielt total verrückt, wenn ich mir deinen Code ansehe. Überall "already defined" und "is not defined". So ein Linter-Plugin ist eine nette Ergänzung zu jeder Entwicklungsumgebung und jedem Editor. Du solltest evtl. auch mal einen installieren.


    Was dein Problem angeht: Asynchrone Abläufe lassen sich hervorragend mit Promise darstellen ("Wenn du fertig bist mit ..., dann mach ..."). Ich sehe in deiner "package.json" kein "engine"-Feld, aber von deinem Quellcode würde ich davon ausgehen, dass du auch Node Versionen < 4 unterstützen willst. Dann brauchst du ein Promise-Polyfill wie promise oder bluebird.


    Es würde sich anbieten, dass dein Modul einen EventEmitter zurück gibt. Wie bei "dgram", der auch EventEmiter im __proto__ hat, können deine User dann die Device-Events mit .on() und .once() abonnieren.
  • Danke für deine Antwort! :) Mir ist bewusst, dass der Code aktuell keinen Schönheitspreis gewinnt ;) Für mich stand zuerst im Vordergrund, den vorhandenen Port möglichst 1:1 funktionierend zu portieren und dann umzubauen. Hätte ich erst versucht, es sauber zu machen und eine andere Struktur zu wählen, wäre das Ziel denke ich sehr viel schwieriger erreichen zu gewesen.
    Also im Endeffekt habe ich mir auch noch keine Gedanken gemacht, welche NodeJS Version ich unterstützen möchte oder ähnliches.

    Hast du im Zusammenhang mit den von dir erwähnten Möglichkeiten ggf. weitere Links zu Literatur, mit der ich mir das vernünftig aneignen kann? Alternativ, mir sogar lieber, vielleicht etwas was funktioniert und mir als Beispiel dienen kann? Bin wie geschrieben noch am Anfang und bewege mich da gerade in einen neuen Bereich und muss einige Wissenslücken schließen :)