太神奇了,昨晚作了個夢,夢中我悟出一個道理:凡是涉及到異步操做並且須要返回值的函數,必定要封裝成 Promise 的形式,假如返回值取決於多個異步操做的結果,那麼須要對每一個異步操做進行狀態的設計,並且須要封裝一個 next 函數。😂😂😂,到了晚上才覺到頗有意思,因此結合 ajax 設置最短返回時間 和 最大返回時間進行實踐: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') })
上面的運行結果符合預期,原本夢中還有另一個有意思的東西,可是太模糊了就搞忘記了,下次必定早點記錄。異步