前言
最开始的时候,没有分析需求,直接开始写。
写到一半发现没法符合异步需要。才发现还需要观察者模式帮忙。
这次从头开始。先分析需求。
一、需求明细
Promise.prototype上的属性
基本点
- Promise是个构造器,接受一个函数作为参数
- 有三种状态:pending/rejected/fulfilled
- Prototype的几种基本方法:then(fulfilled执行)/catch(rejected执行)/finally(非pending执行)
- 链式调用:需要返回 this
- 需要观察者模式——以应对异步的情况
一些方法的细节:就近原则,有 rejectedFn 则不走 catch,无则走 catch
完善点
Promise还有以下方法:all、allSettled、race、any
二、代码
错误代码:没有考虑异步的情况。。。
第一个纯同步函数,执行成功。 第二个异步函数,没有执行成功。(原因是立即执行,这个时候 status => pending)
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function Promise(fn) {
this.status = PENDING
this.result = ''
this.reason = ''
this.resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED
this.result = value
}
}
this.reject = (value) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = value
}
}
fn(this.resolve, this.reject)
}
Promise.prototype.then = function(resolveFunc, rejectFunc) {
if (typeof resolveFunc === 'function' && this.status === FULFILLED) {
resolveFunc(this.result)
} else if (typeof rejectFunc === 'function' && this.status === REJECTED) {
rejectFunc(this.reason)
}
return this
}
Promise.prototype.finally = function(finaFunc) {
if (typeof finaFunc === 'function' && this.status !== PENDING) {
finaFunc.call(this.result || this.reason)
}
}
let p = new Promise(resolve => {
resolve(true)
}).then(res => {
console.log('无异步', res)
}).finally(res => {
console.log('finally', res)
})
let pAsync = new Promise(resolve => {
setTimeout(() => {
console.log('god')
resolve(true)
}, 2000)
}).then(res => {
console.log('异步', res)
}).finally(res => {
console.log('finally:', res)
})
结果
- 同步函数正常执行
- 异步函数,then、finally都没有执行
考虑异步的情况(利用观察者模式,在pending的时候订阅fulfilled-status、rejected-status)
错误代码:使用一个对象来存储“订阅者”的函数,多个 then 方法的情况会有问题
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function Promise(fn) {
this.status = PENDING
this.result = ''
this.reason = ''
this.resolveObj = null
this.rejectedObj = null
this.resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED
this.result = value
this.resolveObj && this.resolveObj(this.result)
}
}
this.reject = (value) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = value
this.rejectedObj && this.rejectedObj(this.reason)
}
}
fn(this.resolve, this.reject)
}
Promise.prototype.then = function(resolveFunc, rejectFunc) {
if (this.status === PENDING) {
this.resolveObj = resolveFunc
this.rejectedObj = rejectFunc
} else if (typeof resolveFunc === 'function' && this.status === FULFILLED) {
resolveFunc(this.result)
return this
} else if (typeof rejectFunc === 'function' && this.status === REJECTED) {
rejectFunc(this.reason)
return this
}
}
let pDefer = new Promise(resolve => {
setTimeout(() => {
resolve('pDefer result')
}, 1000)
})
pDefer.then(res => {
console.log('第一个', res)
})
pDefer.then(res => {
console.log('第二个', res)
})
正确的结果应该是:
正确代码:使用数组来存放“订阅者”函数们
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function Promise(fn) {
this.status = PENDING
this.result = ''
this.reason = ''
this.resolveFnArr = []
this.rejectFnArr = []
this.resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED
this.result = value
this.resolveFnArr.forEach(fn => fn(this.result))
}
}
this.reject = (value) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = value
this.rejectFnArr.forEach(fn => fn(this.reason))
}
}
try {
fn(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
Promise.prototype.then = function(resolveFunc, rejectFunc) {
if (this.status === PENDING) {
typeof resolveFunc === 'function' && this.resolveFnArr.push(resolveFunc)
typeof rejectFunc === 'function' && this.rejectFnArr.push(rejectFunc)
} else if (typeof resolveFunc === 'function' && this.status === FULFILLED) {
resolveFunc(this.result)
return this
} else if (typeof rejectFunc === 'function' && this.status === REJECTED) {
rejectFunc(this.reason)
return
}
}
Promise.prototype.finally = function(finaFunc) {
if (typeof finaFunc === 'function' && this.status !== PENDING) {
finaFunc.call(this.result || this.reason)
}
}
let pDefer = new Promise(resolve => {
setTimeout(() => {
resolve('pDefer result')
}, 1000)
})
pDefer.then(res => {
console.log('第一个', res)
})
pDefer.then(res => {
console.log('第二个', res)
})
符合需要