• There is already a simple State Machine implementation in Espruino:
    https://www.espruino.com/modules/StateMachine.js

    State transitions are triggered by calling

    sm.signal();
    

    However, this expects that the "signal" function of the respective current state synchronously executes some operations and then returns the information what should be the next state to transition to. But how can I handle it if the "signal" function does some asynchronous operations (based on chained Promises). In this case, I cannot immediately decide what the next state should be. I just could return nothing, but then there would be no state transition. I cannot "await" the chained Promises. Actually, I don't see a way to do the state transition at the end of the Promises chain.

    Any clever ideas?

    Update 2019-01-08 : After trying out different approaches I think I could emit events. So the state transitions would be somehow triggered by the receipt of events. And it is no problem to emit events in chained Promises.

  • Personally, if you're trying to do something async you might be better off writing your own state machine system from scratch.

    However, I guess if you think about it, there's actually an intermediate state where you were in one state, you got the signal, and now you're waiting until the code completes async and you can move to the next state.

    If you had state 1 and state 2, this could be state 1_busy:

    • In state 1
    • Signal received : stuff happens, move to state 1_busy
    • Stuff completes async, move to state2

    So in that case I think you can do it with the current system. The handler for state 1 returns 1_busy, and then it sends a signal to the FSM when it properly completes, which causes 1_busy to change to 2?

  • Im am not completely sure, but there seems to be a simple solution with the already existing Espruino StateMachine module:

    Why no do the actual asynchronous work in the "enter" function of each state, and then trigger a state transition in the last "then" block of the chained Promises as follows:

    function enterOne() {
        console.log("Enter One...");
    
        new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('good');
            }, 5000);
        })
        .then((result) => {
            sm.signal(result);
        })
        .catch(() => {
            sm.signal('bad');
        });
    };
    

    In the "signal" function of the respective state there could be code that decides - based on the parameter on the "signal" call (here: 'good' or 'bad') - to which new state to transition:

    function signalOne(result, e) { 
    
        console.log("signal one with parameters", result, e);
        if ('good' === result) {
            return {state:'Two', wait:(e)?e:0};
        } else if ('bad' === result) {
            return {state:'Error', wait:(e)?e:0};
        }
    };
    

    I think this will fit my needs.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

How to handle asynchronous operations in StateMachine?

Posted by Avatar for wklenk @wklenk

Actions