https://d226lax1qjow5r.cloudfront.net/blog/blogposts/learn-and-apply-xstate-with-vonage-video/Blog_XState_VideoAPI_1200x600.png

Lernen und Anwenden von XState mit Vonage Video

Zuletzt aktualisiert am May 4, 2021

Lesedauer: 13 Minuten

In den letzten Monaten habe ich mehr gehört über Zustandsautomaten die für die Front-End-Entwicklung verwendet werden. Die Idee eines Zustandsautomaten ist, dass er nur eine endliche Anzahl von Zuständen hat und sich zu jedem Zeitpunkt nur in einem Zustand befinden kann. Konzeptionell ist dies für die App-Entwicklung sehr sinnvoll - es gibt nur eine bestimmte Anzahl von Zuständen.

Das Konzept der Zustandsautomaten und Zustandsdiagramme ist nicht neu, und es hat seine Wurzeln auch nicht in der Frontend-Entwicklung. Es handelt sich um ein mathematisches Modell, das in vielen Dingen um uns herum verwendet wird. Zum Beispiel kann ein Licht sein OFF oder ON. Man kann alles mit einem Zustandsautomaten beschreiben, auch wenn dies ein einfaches Beispiel ist.

On and off states of lightbulbOn and off states of lightbulb

Einführung in XState

Die Verwendung eines Zustandsautomaten in der Frontend-Entwicklung ist mit der Erstellung des Pakets XState. XState hilft bei der Definition von Zustandsautomaten, der Erstellung von Ereignissen und Effekten und der Steuerung des gesamten Anwendungsablaufs. XState verwendet JavaScript-Methoden und -Objekte, um den Zustandsautomaten zu beschreiben.

Das Glühbirnenbeispiel von oben würde wie folgt geschrieben werden:

const lightBulb = Machine({
  id: 'lightBulb',
  initial: 'off',
  states: {
    off: {
      on: {
        TURN_ON: 'on'
      }
    },
    on: {
      on: {
        TURN_OFF: 'off',
      }
    }
  }
});

Der hier definierte Zustandsautomat zeigt die beiden Zustände der Glühbirne, OFF und ONund die Übergänge aus den Ereignissen TURN_ON und TURN_OFF.

Das Objekt selbst ist nicht sehr komplex zu lesen, aber je komplexer der Zustandsautomat wird, desto schwieriger kann es sein, ihn zu verstehen. XState hat ein Werkzeug entwickelt, das dabei hilft - den XState-Visualisierer.

Mit dem XState-Visualizer können Sie sehen, wie die Zustandsautomaten funktionieren und interaktiv sind, so dass das Spielen mit ihnen Spaß macht. Wenn Sie sich den Code für den Automaten ansehen möchten, können Sie auch auf die Schaltfläche "Code" klicken, um einen Blick darauf zu werfen.

Erstellen eines Vonage Video-Statusdiagramms

Als ich mich daran machte, Zustandsautomaten und XState zu erlernen, war mein übergeordnetes Ziel, eine Anwendung ähnlich wie Google Meet zu erstellen, die Vonage Video. Die Anwendung würde es einem Benutzer ermöglichen, einen Besprechungsraum zu erstellen, die URL freizugeben und eine Besprechung mit mehreren Streams abzuhalten. Um das zu erreichen, musste ich einige der verschiedenen Concepts für Zustandsdiagramme lernen und wie man diese in XState darstellt.

Ich habe festgestellt, dass es nicht einfach ist, die möglichen Anwendungszustände zu durchdenken. Es gibt viele Möglichkeiten, die es zu erforschen gilt, und um die richtige Lösung zu finden, bedarf es einiger Versuche und Fehler.

Im weiteren Verlauf dieses Artikels werden einige grundlegende Concepts behandelt und eine Zustandsdiagramm-Visualisierung erstellt, die den eventuellen Zustandsautomaten nachahmt. Ich werde auch einige zusätzliche Links und Ressourcen zur Verfügung stellen, so dass Sie auf eigene Faust forschen können.

Zustände und Zustandsknoten

A Zustand ist eine Darstellung einer Maschine zu einem bestimmten Zeitpunkt. Dieser Zeitpunkt kann definiert werden und dann zu einem Zustandsknoten in XState, der als Konfiguration erfasst wird.

In meiner Vonage Video-Anwendung gibt es verschiedene Lösungsmöglichkeiten, aber ich habe festgestellt, dass die Beschreibung der Zustände in möglichst einfachen Begriffen der beste Weg ist, um zu einem brauchbaren Ergebnis zu kommen.

Erstellen einer Maschine erfolgt nach dem folgenden Muster:

const machine = Machine(state_nodes, options)

Mit Blick auf einen Video-Zustandsautomaten gibt es zwei zusammengesetzte Zustände - connected und disconnected.

Zwei Zustandsknoten mögen allzu vereinfacht erscheinen, aber nach einigem Ausprobieren gibt es nur zwei Zustände. Jeder dieser Zustände ist jedoch komplexer als ein atomarer Knoten (ohne Kinder). Anstatt jeden möglichen Zustand auf der obersten Ebene zu erstellen, hilft uns XState mit hierarchischen und parallelen Zustandsknoten bei der Organisation.

Hierarchische Zustandsknoten

XState bietet die Möglichkeit, verschachtelte Zustände zu erstellen, die hierarchical Zustandsknoten. Wenn wir die Maschine zum ersten Mal starten, können wir sie auf idle setzen, da die Maschine dann zwar bereit ist, aber nichts tut. Warum nicht einfach einen weiteren atomaren Zustandsknoten auf oberster Ebene erstellen?

Das Hinzufügen von Zuständen auf der obersten Ebene wird als "Zustandsexplosion" bezeichnet und ist ein typischer Nebeneffekt von endlichen Zustandsautomaten. Da Vonage Video technisch gesehen immer noch ein disconnectedist, macht die Verschachtelung idle sinnvoll, da das Video sowohl abgeschaltet als auch im Leerlauf ist. Ein weiterer disconnected Unterzustand sollte sein ready. Der disconnected.ready Zustand würde kurz vor dem Übergang zum connected Zustand. Der Zustandsautomat hat auch einen Zustandsknoten zwischen idle und ready um alles einzurichten. Dieser Zwischenzustand kann als die init Phase.

Der Zustandsautomat würde nun wie folgt aussehen:

Sie werden feststellen, dass es derzeit keine Möglichkeit gibt, sich zwischen den beiden Knoten zu bewegen. Wir werden Ereignisse und Aktionen in einem Moment behandeln.

Parallele Zustandsknoten

A parallel Zustandsknoten ermöglicht es der Anwendung, sich in allen Unterzuständen gleichzeitig zu befinden. Der Vonage Video Zustandsautomat ist stark ereignisgesteuert, daher müssen wir mehrere Zustände gleichzeitig verwalten.

Um anzugeben, dass ein Zustandsknoten parallel ist, verwenden wir type:parallel in der Konfiguration. Nach dem Übergang zu connectedwerden drei parallele Zustände auftreten - session, publisher, und subscribers. Jeder dieser Zustände richtet Ereignisse und Ereignis-Listener ein, um die Reaktionen des Vonage Video-Dienstes zu steuern.

Die resultierende Visualisierung sieht wie folgt aus:

Mit diesen primären Zuständen können wir steuern, was unsere Anwendung zu bestimmten Zeiten anzeigt. Derzeit können wir jedoch nicht zwischen den Zuständen wechseln. Werfen wir einen Blick auf Ereignisse und Übergänge.

Ereignisse und Übergänge

Da ein Zustandsknoten nur die Konfiguration eines einzelnen Zustands ist, gibt es naturgemäß keine Möglichkeit, von einem Zustand in einen anderen zu wechseln, ohne dies im Zustandsknoten zu deklarieren.

Jeder Knoten lauscht auf ein gesendetes Ereignis auf Übergang in den nächsten Zustand. Im Beispiel mit der Glühbirne bedeutet das TURN_ON gesendete Ereignis die Maschine an, den Übergang zu on.

Übergänge gibt es nur zwischen Knoten der obersten Ebene und innerhalb hierarchischer Knoten. Parallele Knoten dürfen nicht untereinander übergehen. Für unsere Vonage Video-App bedeutet dies Folgendes:

  1. Wenn die Seite fertig ist, können wir ein START Ereignis. Dieses Ereignis wird den Status auf disconnected.init.

  2. Der disconnected.init Zustand wird beendet, sobald das VIDEO_ELEMENT_CREATED Ereignis ausgelöst wurde.

  3. Sobald wir die disconnected.readyerreicht haben, können wir dem Benutzer erlauben, eine Verbindung herzustellen, indem wir das CONNECT Ereignis und Übergang zu connected.

  4. Wenn die Anwendung das Ereignis DISCONNECT übergeben, würde der Zustandsautomat die Verbindung unterbrechen.

Die Deklaration eines Ereignisses und eines Übergangs in XState erfolgt nach dem folgenden Muster:

on: {
  EVENT_DESCRIPTOR: 'nextState'
}

Sie können dem Übergang auch bestimmte Aktionen hinzufügen. Ich empfehle Ihnen, die Abschnitte über interne und externe Übergänge in der Dokumentation zu lesen. Darin werden die verschiedenen Arten von Übergängen sehr detailliert beschrieben.

Bewachte Übergänge

Sie haben vielleicht bemerkt, dass einer der Übergänge einen cond Knoten in der Transition hat. Diese Bedingung nennt man eine guarded Übergang. Geschützte Übergänge schützen die Maschine davor, in einen Zustand überzugehen, der unter bestimmten Bedingungen nicht zulässig ist. In diesem Fall möchte ich den Übergang zu ready übergehen, bis sowohl das Token als auch das Video-Element erstellt sind.

on: {
  'VIDEO_ELEMENT_CREATED': {
    target: 'ready',
    cond: 'checkToken'
  }
}

Die Schutzbedingung checkToken ist ein benannter Verweis auf das Guards-Objekt im Options-Parameter, der an die Maschine gesendet wird:

const video = Machine(
  state_nodes,{
  guards: {
    checkToken: () => true
  }
});

Kontext

Um für eine Anwendung nützlicher zu sein, benötigt unser Zustandsautomat einen länger lebenden Zustand, der als extended state, oder context. Das Kontextobjekt wird über verschiedene Effekte mit der assign() Methode.

Apropos Aktionen, lassen Sie uns diese jetzt angehen und den Rest des Skeletts fertigstellen.

Aktionen und Dienstleistungen

Es gibt so genannte "Nebeneffekte" in Zustandsautomaten, die XState in eine von zwei Kategorien einteilt:

  1. "Fire-and-forget" - der Effekt sendet keine Ereignisse

  2. Aufgerufen - wenn das Senden von Ereignissen erforderlich ist

Aktionen

Aktionen sind Einzeleffekte und gehören zu den häufigsten Effekten in der Video State Machine. Sie können Aktionen verwenden, wenn Sie einen Knoten betreten oder verlassen oder während eines Übergangs. Das Verständnis der Reihenfolge von Aktionen ist unglaublich wichtig.

Eine hervorragende Ressource zum Erlernen der Aktionsreihenfolge (und aller anderen Themen von XState) ist ein Video, das von @kyleshvlin drüben bei Egghead.io. Es hat mir geholfen zu verstehen, wie Aktionen abgefeuert werden.

Der Großteil der Aktionen für diese Maschine dreht sich um die Aktualisierung des Kontexts als Übergang. Wenn Ereignisse aufgerufen werden, können wir die Aktion verwenden, um die assign() Methode:

on: {
  'SOME_EVENT': {
      actions: assign({'someContext': (ctx, e) => e.someValue})
  } 
}

Dienstleistungen

Aufgerufene Dienste sind der andere Haupteffekt im Video-Zustandsautomaten. Um Versprechen und Ereignis-Listener zu verwenden, müssen Sie einen Dienst aufrufen. Dieses Konzept war für mich bei weitem am schwierigsten zu begreifen. Die größte Schwierigkeit bestand darin, zu verstehen, dass ein aufgerufener Dienst anhält, wenn der Zustand beendet wird. Wenn man zu schnell übergeht, verschwindet das Versprechen oder der Rückruf.

Es gibt zwei primäre Dienste, die ich in der Video-Zustandsmaschine verwende: Versprechen und Rückrufe. Der invoke promises Dienst ermöglicht es dem Zustandsautomaten, ein Versprechen zu verwenden, um entweder aufzulösen oder zurückzuweisen und dann entsprechend zu handeln. Ich habe dies verwendet, um mit dem Server asynchron zu interagieren und dann den Kontext zu aktualisieren, wenn er fertig ist.

Die Funktionssignatur der aufgerufenen Versprechen sieht wie folgt aus:

src: (context, event) => new Promise((resolve, reject) => {
  if (event.error) reject('Rejected')
  resolve('Resolved')
}),
onDone: {/*success transition*/}
onError: {/*error transition*/}

Der zweite und wahrscheinlich wichtigste Teil dieser Maschine ist die invoked callbacks. Die Architektur von Vonage Video stützt sich stark auf Ereignisse und Ereignislisten. In einem Zustandsautomaten werden diese über einen Callback eingerichtet. Ich möchte Ihnen ein Beispiel zeigen:

invoke: {
  id: 'initPublisher',
  src: (ctx) => (cb) => {
    let publisher = initPublisher(pubOptions);
    publisher.on('videoElementCreated', (e) => {
      cb({ type: 'VIDEO_ELEMENT_CREATED', publisher: publisher })
    })
    return () => publisher.off('videoElementCreated');
  }
}

Die Funktionssignatur eines aufgerufenen Rückrufs sieht wie folgt aus:

src: (context, event) => (callback, onReceive) => {
  
  callback('EVENT');
  onReceive(event) => { callback('OTHER_EVENT') };

  return () => cleanup()
};

Unter Verwendung von Aktionen und Diensten sieht unser Vonage Video-Zustandsautomat nun wie folgt aus:

Vergessen Sie nicht, herumzuklicken, und klicken Sie auf die Registerkarte code um zu sehen, wie der Zustandsautomat in der Konfiguration aussieht.

Ressourcen und Nachbereitung

Ok - Sie haben es also bis hierher geschafft.

I'm proud of you!I'm proud of you!

Wenn Sie sich zum ersten Mal mit XState beschäftigen, ist es eine Menge auf einmal zu verarbeiten. Ich bin immer noch dabei, neue Wege zu erforschen und zu erlernen, um Dinge zu tun. Dieser Beitrag ist nur ein kleiner Teil dessen, was es da draußen gibt. Während Sie lernen - hier sind ein paar großartige Ressourcen, die Sie sich ansehen sollten

Wenn Sie Fragen zu XState haben, können Sie sich gerne an uns wenden, und wir können gemeinsam etwas Neues lernen!

Teilen Sie:

https://a.storyblok.com/f/270183/384x384/444c073b5e/kellyjandrews.png
Kelly J AndrewsEhemaliges Teammitglied

Kelly J. Andrews ist eine Entwicklerin, die sich für Nexmo einsetzt. Sie bastelt seit über 30 Jahren an Computern und verwendete BASIC zum ersten Mal im Alter von 5 Jahren.

Erst als er 1997 seine erste Webseite erstellte und JavaScript zum ersten Mal ausprobierte, fand er seine wahre Berufung. Kelly kämpft jetzt für JavaScript, testbaren Code und schnelle Lieferung.

Er singt Karaoke, zaubert oder feuert die Cubs und die Fighting Irish an.