状态机模式 与 ajax 的结合运用
太神奇了,昨晚做了个梦,梦中我悟出一个道理:凡是涉及到异步操作而且需要返回值的函数,一定要封装成 Promise 的形式,假如返回值取决于多个异步操作的结果,那么需要对每个异步操作进行状态的设计,而且需要封装一个 next 函数。😂😂😂,到了晚上才觉到很有意思,所以结合 ajax 设置最短返回时间和最大返回时间进行实践:
const PENDING = 'PENDING'
const RESOLVED = 'RESOLVED'
const REJECTED = 'REJECTED'
const FULLFILLED = 'FULLFILLED'
/**
* @desc 异步操作模拟
* @param time 响应时间
* @param isError 是否抛错
*/
const mock = (time, isError) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (!isError) {
resolve({ user: 'ManbaX' })
} else {
reject('request error')
}
}, time)
})
}
/**
* @desc 生产不同类型请求的工厂函数
* @param time 响应时间
* @param isError 是否抛错
*/
var RequestFactory = function (time, isError) {
var request = function () {
return new Promise((resolve, reject) => {
var min = PENDING
var max = PENDING
var state = PENDING
var res = null
var next = function (name) {
const cb = function () {
if (state === RESOLVED) {
resolve(res)
} else {
reject(res)
}
}
if (name === 'res' && min === FULLFILLED) {
cb()
}
if (name === 'min' && (state === RESOLVED || state === REJECTED)) {
cb()
}
if (name === 'max' && state === PENDING) {
reject('timeout')
}
}
setTimeout(() => {
min = FULLFILLED
next('min')
}, 500)
setTimeout(() => {
max = FULLFILLED
next('max')
}, 1000)
mock(time, isError).then(data => {
res = data
state = RESOLVED
next('res')
}).catch(error => {
res = error
state = REJECTED
next('res')
})
})
}
return request
}
// 不超时, 不返回错误
console.time('r1')
RequestFactory(200)().then(res => {
console.log('data: ', res)
}).finally(() => {
console.timeEnd('r1')
})
// 不超时, 返回错误
console.time('r2')
RequestFactory(200, true)().catch(err => {
console.log('error', err)
}).finally(() => {
console.timeEnd('r2')
})
// 超时
console.time('r3')
RequestFactory(2000)().catch(res => {
console.log('error: ', res)
}).finally(() => {
console.timeEnd('r3')
})
上面的运行结果符合预期,本来梦中还有另外一个有意思的东西,但是太模糊了就搞忘记了,下次一定早点记录。