Finite State Machines are an old concept in computer science that help you remain bug-free while you manage complex state interactions in your application. In this lesson, I'll show you how to implement one so you have an understanding of the fundamentals of what they do.
This is based on my blog post: Implementing a simple state machine library in JavaScript
Instructor: [0:00] Statecharts.github.io has a page, what is a state machine? Down here, it gives a definition of what a state machine really needs to have. We're going to use this as a reference for implementation of our own state machine library.
[0:15] What I am going to do here is I am going to copy all of this, and I've got a code sandbox here where I have written out the type of machine that I want to make. We're just going to have a toggle.
[0:24] We start out with an initial state of off, and then we transition to a state of on, and then we transition again with the switch to the state of off.
[0:34] Here's what we need to do to make that happen for the definition of our state, and then when our state machine is running and the transition happens, these are the things that need to happen for that.
[0:46] I am going to copy that. We'll paste it over here. Let's go ahead and make this thing happen. First, we need to create a machine. I'll say our machine equals createMachine, and we'll pass a state machine definition object.The first thing for our state machine definition object is one state is defined as the initial state.
[1:06] Let's go ahead and we'll define our initial state is off. That's what we want it to be right here from the get-go and we'll probably want to have a definition for all of our states as well. I'll have an off-state definition here and an on-state definition here and then when the machine starts to execute, it automatically enters this state.
[1:26] We'll get to that when we implement the create machine function. That gets that taken care of and then each state can define actions that occur when a machine enters or exits these states. Actions are typically for side effects. We need an enter and exit action for each one of these.
[1:42] I'm going to go up to off and we'll have an actions definition here and we'll have an on-enter that's a function and an on-exit that's a function. Then we'll do the same thing for our on-state here. Just so that we can check our work, I'm going to go ahead and add a console log off on enter and we'll do a console log off on exit.
[2:06] We can take a look at those later. I'll just copy paste these here and we'll change that from off to on so we can differentiate those. We've taken care of that one. Next, we have each state can define events that trigger a transition so we want to make transitions a part of our state definition here.
[2:23] For each one of these state definitions, we're going to have a transitions object. I have one there and one for our on here. That takes care of that one. Then the transition defines how a machine would react to an event so the event being specifically what we pass here as a second argument when we call a transition. We have a switch event here, and we need to define a switch transition for each one of these because we switched from off and then we switched from on.
[2:51] The implication here is that we would exit one state and enter another state. All we really need to define is what state are we going to transition to as part of this switch transition. For the off, we'll have a switch transition definition here, and we'll have a target state that we want to go to from this transition to the other, which will be on, in this case.
[3:13] Then we'll just copy this down for our transition here, and we're going to transition from on to off. That's our switch transition definition here. We can get rid of that. The last one here is a transition can define actions that occur when the transition happens, and actions will typically have side effects.
[3:32] This one actually is pretty similar to on-enter and on-exit. We just want to have some way to execute some random code when we transition from one thing to another. At first, I read this and I thought that seems like basically the same thing as on-enter and turn on-exit, just two ways to do the same thing.
[3:49] In a real world scenario, you're going to have state A that can transition to state B, and we want to have something being logged when that happens but not when state C transitions to state B. Having the ability to transition some of the side effects code in either of those scenarios is pretty important.
[4:06] I'm going to get rid of this and we'll add an action which will just be a function and will console.log transition action for switch events in on state. Then we'll copy the same thing for our off state, and we'll switch this to off state. We can check that when we run all these.
[4:29] That takes care of our state machine definition object. Now, we need to implement the create machine function so that it does all of these things when we make a transition. I'm going to make a function called, create machine, and this is going to take my state machine definition. This is going to create a machine, and it's going to return a machine.
[4:51] That machine needs to have its value sent to the state machine definition.initial state. That's where we're getting that right there. We do need to spell things correctly so I'm just going to copy paste that. There we go. Cool. This machine that we're using further down here, we're using machine.transition.
[5:12] We'll come back up here and add a transition function here. That transition function, if we scroll down again, is going to accept the current state and an event for switching that current state to something new. I'm going to come back up here and we'll take our current state and an event.
[5:32] Then we'll return the machine's value. This is where all of this magic is going to happen. The first thing, the event is checked against the current states transitions. What we need to do here is grab the transitions object and determine the destination transition.
[5:48] I'll make a current state definition to get that from the state machine definition current state. The current state is going to be the string off or the string on. We're going to grab that state definition from the state machine definition.
[6:04] With that current state definition, which is going to be the subject or the on object, we need to get the transitions property. Let's get our destination transition from the current state definition.transitions of the event. We grab this transitions object. I'm grabbing the switch property from that transitions object.
[6:30] I just noticed that this action is not part of the switch objects. Let's put that in there. We'll make sure that the on is doing the proper thing there as well, because this action is definitely associated to the specific transition. Great. Now that we have the destination transition, that takes care of checking against the current states transitions.
[6:51] If a transition matches the event, that transition happens. That means we need to exit early if there is no destination transition. That could happen if somebody says swap instead of switch. We have no transition for that so we're just going to ignore that transition.
[7:07] Let's come up here. We'll say, if there's no destination transition, then we'll return. That takes care of this one. By virtue of a transition happening, states are exited and entered and the relevant actions are performed. What we need to do here is we need to get the transition action, the on-exit action and at the on-enter action for the appropriate states.
[7:30] For transitioning from off to on, then we're going to exit the off. We're also going to need to execute the action for this particular transition. We're going to enter the on. Those are the three that we need to execute for that transition.
[7:45] Let's go ahead and grab those functions. First, we're going to need the destination state, and we can get that from the destination transition.target. Then we'll need to get the destination state definition from the state machine definition at that destination state.
[8:01] With that information, we now can execute the destination transition action and then we can execute the current state definition actions on exit. Then we'll execute the destination state definition actions on enter. That takes care of all the actions for this transition.
[8:24] This last one, the machine, immediately is in the new state ready to process the next event. I'll get rid of that. That's simple enough. We would simply say, machine.value equals destination state. With that, everything is implemented so we can scroll down here.
[8:40] Initially, we're going to get that machine value, which is going to be set to our initial state for this machine. That should be off. We're going to console.log that and then we'll transition with that state using the switch event that should switches over to the on state and then we'll transition with the switch again.
[8:59] That should get us back to the off state. Let's go ahead and open up our preview to get our console. Here, we can take a look at that. Our current state is off, and then we execute the transition action for the switch in the off state.
[9:12] We're transitioning from the off state with the switch event and then off gets exited and on gets entered. Then our current state is on and then we transition with switch for the on state and on gets exited, off gets entered, and then our current state is off.