太神奇了,昨晚做了個夢,夢中我悟出一個道理:凡是涉及到非同步操作而且需要返回值的函式,一定要封裝成 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')
})
console.time('r4')
RequestFactory(2000)().catch(res => {
console.log('error: ', res)
}).finally(() => {
console.timeEnd('r4')
})
上面的執行結果符合預期,本來夢中還有另外一個有意思的東西,但是太模糊了就搞忘記了,下次一定早點記錄。