状态模式:当一个对象里面有状态变化,而且当状态发生改变时,会触发一个逻辑(或者行为)。特别当状态比较多时,那么就需要状态模式,不能总是写if else 来控制。
生活中,红绿灯就是一个很好的状态模式的例子。
我们先来看一下简化版状态模式的类图。
我们以红绿灯为例,来写一下代码。
class State {
constructor(color) {
this.color = color;
}
handle(context) {
context.setState(this);
}
}
class Context {
constructor() {
this.state = null;
}
setState(state) {
this.state = state;
}
getState() {
return this.state;
}
}
const context = new Context();
const green = new State("绿灯");
const yellow = new State("黄灯");
const red = new State("红灯");
green.handle(context);
console.log(context.getState().color);
red.handle(context);
console.log(context.getState().color);
yellow.handle(context);
console.log(context.getState().color);
这只是一个简单的例子,演示了如何将状态和操作对象实现分离。
javascript-state-machine 这是一个JS的状态管理库,用法非常简答
我们还是使用红绿灯例子举例
const StateMachine = require("javascript-state-machine");
const fsm = new StateMachine({
init: "red", //触式默认状态
transitions: [
{ name: "rTOy", from: "red", to: "yellow" }, //定义变化
{ name: "yTOg", from: "yellow", to: "green" },
{ name: "gTOr", from: "green", to: "red" },
],
methods: { //定义变化 触发的逻辑
onRTOy: function () {
console.log("红灯变成黄灯");
},
onYTOg: function () {
console.log("黄灯变成绿灯");
},
onGTOr: function () {
console.log("绿灯变成红灯");
},
}
})
const flag = setInterval(()=>{
if (fsm.is("red")) { //使用is来判断状态
fsm.rTOy(); //调用定义好的方法
} else if (fsm.is("yellow")) {
fsm.yTOg();
} else {
fsm.gTOr();
}
}, 2000);
我们在看一个复杂一点的例子,我们使用上面的那个库,来实现一个非常简单的promise(因为Promise的状态有三个pending fulfilled rejected)
当状态从pending到fulfilled时,那么就调用resolve 当状态从pending到rejected时 ,那么调用reject
很明显这里面有状态的变化,所以我们使用状态模式写一下。
const StateMachine = require("javascript-state-machine");
const fsm = new StateMachine({
init: "pending",
transitions: [
{ name: "resolve", from: "pending", to: "fulfilled" },
{ name: "reject", from: "pending", to: "rejected" },
],
methods: {
onResolve: function (state, resolveFn) { //将成功的所有回调全部调用
resolveFn.forEach((fn) => fn());
},
onReject: function (state, rejectFn) {//将失败的所有回调全部调用
rejectFn.forEach((fn) => fn());
}
}
})
class MyPromise {
constructor(fn) {
this.resolveCallBack = [];
this.rejectCallBack = [];
fn((target) => {//resolve 函数即把状态把pending转为fulfilled
fsm.resolve(this.resolveCallBack);
}, () => {//reject 函数即把状态把pending转为rejected
fsm.reject(this.rejectCallBack );
})
}
then(resolve = () => {}, reject = () => {}) {
this.resolveCallBack.push(resolve); //添加成功回调
this.rejectCallBack.push(reject);
}
}
function loadImg(src) {
return new MyPromise((resolve, reject) => {
const img = document.createElement("img");
img.onload = function () {
resolve();
}
img.onerror = function () {
reject();
}
img.src = src;
})
}
const result = loadImg("https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3034041308,2252600183&fm=26&gp=0.jpg")
result.then(() => {
console.log("成功了")
}, () => {
console.log("失败了")
})
关键的地方 我已经加上了注释,假如你了解promise的工作原理,那么理解起来就不难,不然的话,需要一些时间。
上面代码 演示了如何使用状态模式来实现promise的几种状态管理,当一个对象里面有许多状态而且状态的改变会引发变化,那么你可以试试状态模式。