transition is invalid while previous transition is still in progress
This code is an example of what I read Asynchronous Transitions.md。 But did not work properly and what should I do?
var fsm = new StateMachine({
init: 'menu',
transitions: [
{ name: 'play', from: 'menu', to: 'game' },
{ name: 'quit', from: 'game', to: 'menu' }
],
methods: {
onEnterMenu: function() {
console.log('onEnterMenu')
return new Promise(function(resolve, reject) {
setTimeout(function () {
resolve()
}, 1000)
})
},
onEnterGame: function() {
console.log('onEnterGame')
return new Promise(function(resolve, reject) {
setTimeout(function () {
resolve()
}, 1000)
})
},
onLeaveMenu: function() {
console.log('onLeaveMenu')
return new Promise(function(resolve, reject) {
setTimeout(function () {
resolve()
}, 1000)
})
},
onLeaveGame: function() {
console.log('onLeaveGame')
return new Promise(function(resolve, reject) {
setTimeout(function () {
resolve()
}, 1000)
})
}
}
})
fsm.play()
By the time you call fsm.play() the promise inside the onEnterMenu method is not yet resolved. Thus, there is already a pending transition and an exception is thrown as explained in error-handling.md
The way that worked for me, was to explicitly specify an initial state:
var fsm = new StateMachine({
// init: 'menu',
transitions: [
{ name: 'init', from: 'none', to: 'menu' },
{ name: 'play', from: 'menu', to: 'game' },
{ name: 'quit', from: 'game', to: 'menu' }
],
...
});
...and then explicitly initialize:
fsm.init().then(fsm.play.bind(fsm));
This way, you can make sure that the transition to state game will take place after the transition to state menu has been completed.
@georapbox thank you for the explanation! I understand that
Guys, this does not work for me. I'm using the StateMachine.factory, does this make a difference?
const fsm = require('javascript-state-machine');
let fsmFactory = fsm.factory({
init: 'parse',
data: function(input) {
return {
rawInput: input,
command: '',
args: []
}
},
transitions: [
{ name: 'doParse', from: 'none', to: 'parse' },
{ name: 'doParseSingle', from: 'parse', to: 'parseSingle' },
{ name: 'doParseMultiple', from: 'parse', to: 'parseMultiple' },
{ name: 'toEmptyInput', from: 'parse', to: 'emptyInput'}
],
methods: {
onBeforeTransition: function() {
console.log('onBeforeTransition', arguments);
},
onParse: function(state) {
let toParse = this.rawInput;
console.log('onParse', toParse);
if (!toParse) {
this.toEmptyInput();
} else {
this.splitInput(toParse);
}
},
splitInput: function(toParse) {
let input = toParse.split(' ');
this.command = input.shift();
if (input.length) {
this.args = input;
this.doParseMultiple();
} else {
this.doParseSingle();
}
}
}
});
let fsm1 = new fsmFactory('/start');