Promise核心
起步构建
首先声明定义类并声明Promise状态与值,有以下几个细节需要注意。
- executor为执行者
- 当执行者出现异常时触发拒绝状态
- 使用静态属性保存状态值
- 状态只能改变一次,所以在resolve与reject添加条件判断
- 因为 resolve或rejected方法在executor中调用,作用域也是executor作用域,这会造成this指向window,现在我们使用的是class定义,this为undefined。
class MK {
static PENDING = 'pending'
static FULFILLED = 'fulfilled'
static REJECTED = 'rejected'
constructor(executor) {
this.status = MK.PENDING
this.value = null
try {
executor(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject(error)
}
}
resolve(value) {
if (this.status === MK.PENDING) {
this.status = MK.FULFILLED
this.value = value
}
}
reject(value) {
if (this.status === MK.PENDING) {
this.status = MK.REJECTED
this.value = value
}
}
}
const p = new MK((resolve, reject) => {
resolve('mkimq')
})
console.log(p)
THEN
现在添加then方法来处理状态的改变,有以下几点说明
- then可以有两个参数,即成功和错误时的回调函数
- then的函数参数都不是必须的,所以需要设置默认值为函数,用于处理当没有传递时情况
- 当执行then传递的函数发生异常时,统一交给onRejected来处理错误
基础构建
class MK {
static PENDING = 'pending'
static FULFILLED = 'fulfilled'
static REJECTED = 'rejected'
constructor(executor) {
this.status = MK.PENDING
this.value = null
try {
executor(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject(error)
}
}
then(onFulfilled, onRejected) {
if (typeof onFulfilled !== 'function') {
onFulfilled = value => value
}
if (typeof onRejected != 'function') {
onRejected = value => value
}
if (this.status === MK.FULFILLED) {
try {
onFulfilled(this.value)
} catch (error) {
onRejected(error)
}
}
if (this.status == MK.REJECTED) {
try {
onRejected(this.value)
} catch (error) {
onRejected(error)
}
}
}
resolve(value) {
if (this.status === MK.PENDING) {
this.status = MK.FULFILLED
this.value = value
}
}
reject(value) {
if (this.status === MK.PENDING) {
this.status = MK.REJECTED
this.value = value
}
}
}
new MK((resolve, reject) => {
resolve('mkimq')
}).then(
v => {
console.log(v)
},
e => {
console.log(e)
}
)
异步任务
但上面的代码产生的Promise并不是异步的,使用setTimeout来将onFulfilled与onRejected做为异步宏任务执行
then(onFulfilled, onRejected) {
if (typeof onFulfilled !== 'function') {
onFulfilled = value => value
}
if (typeof onRejected != 'function') {
onRejected = value => value
}
if (this.status === MK.FULFILLED) {
setTimeout(() => {
try {
onFulfilled(this.value)
} catch (error) {
onRejected(error)
}
})
}
if (this.status == MK.REJECTED) {
setTimeout(() => {
try {
onRejected(this.value)
} catch (error) {
onRejected(error)
}
})
}
}
PENDING状态
目前then方法无法处理promise为pending时的状态
const p = new MK((resolve, reject) => {
setTimeout(() => {
resolve('mkimq')
})
})
为了处理以下情况,需要进行几点改动
- 在构造函数中添加callbacks来保存pending状态时处理函数,当状态改变时循环调用
constructor(executor) {
...
this.callbacks = []
...
}
- 将then方法的回调函数添加到 callbacks 数组中,用于异步执行
then(onFulfilled, onRejected) {
if (typeof onFulfilled !== 'function') {
onFulfilled = value => value
}
if (typeof onRejected != 'function') {
onRejected = value => value
}
if (this.status === MK.PENDING) {
this.callbacks.push({
onFulfilled: value => {
try {
onFulfilled(value)
} catch (error) {
onRejected(error)
}
},
onRejected: value => {
try {
onRejected(value)
} catch (error) {
onRejected(error)
}
}
})
}
}
- resovle与reject中添加处理callback方法的代码
resolve(value) {
if (this.status === MK.PENDING) {
this.status = MK.FULFILLED
this.value = value
this.callbacks.map(callback => {
callback.onFulfilled(value)
})
}
}
reject(value) {
if (this.status === MK.PENDING) {
this.status = MK.REJECTED
this.value = value
this.callbacks.map(callback => {
callback.onRejected(value)
})
}
}
PENDING异步
resolve(value) {
if (this.status === MK.PENDING) {
this.status = MK.FULFILLED
this.value = value
setTimeout(() => {
this.callbacks.map(callback => {
callback.onFulfilled(value)
})
})
}
}
reject(value) {
if (this.status === MK.PENDING) {
this.status = MK.REJECTED
this.value = value
setTimeout(() => {
this.callbacks.map(callback => {
callback.onRejected(value)
})
})
}
}
链式操作
Promise中的then是链式调用执行的,所以then也要返回Promise才能实现
- then的onReject函数是对前面Promise的rejected的处理
- 但该Promise返回状态要为fulfilled,所以在调用onRejected后改变当前promise为fulfilled状态
then(onFulfilled, onRejected) {
if (typeof onFulfilled !== 'function') {
onFulfilled = value => value
}
if (typeof onRejected != 'function') {
onRejected = value => value
}
return new MK((resolve, reject) => {
if (this.status === MK.PENDING) {
this.callbacks.push({
onFulfilled: value => {
try {
onFulfilled(value)
} catch (error) {
onRejected(error)
}
},
onRejected: value => {
try {
onRejected(value)
} catch (error) {
onRejected(error)
}
}
})
}
})
}
返回类型
如果then返回的是Promise呢?所以我们需要判断分别处理返回值为Promise与普通值的情况
基本实现
then(onFulfilled, onRejected) {
if (typeof onFulfilled !== 'function') {
onFulfilled = value => value
}
if (typeof onRejected != 'function') {
onRejected = value => value
}
return new MK((resolve, reject) => {
if (this.status === MK.PENDING) {
this.callbacks.push({
onFulfilled: value => {
try {
const result = onFulfilled(value)
if (result instanceof MK) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch (error) {
reject(error)
}
},
onRejected: value => {
try {
const result = onRejected(value)
if (result instanceof MK) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch (error) {
reject(error)
}
}
})
}
if (this.status === MK.FULFILLED) {
setTimeout(() => {
try {
const result = onFulfilled(this.value)
if (result instanceof MK) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch (error) {
reject(error)
}
})
}
if (this.status === MK.REJECTED) {
setTimeout(() => {
try {
const result = onRejected(this.value)
if (result instanceof MK) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch (error) {
reject(error)
}
})
}
})
}
代码复用
现在发现pendding、fulfilled、rejected 状态的代码非常相似,所以可以提取出方法Parse来复用
then(onFulfilled, onRejected) {
if (typeof onFulfilled !== 'function') {
onFulfilled = value => value
}
if (typeof onRejected != 'function') {
onRejected = value => value
}
return new MK((resolve, reject) => {
if (this.status === MK.PENDING) {
this.callbacks.push({
onFulfilled: value => {
this.parse(onFulfilled(this.value), resolve, reject)
},
onRejected: value => {
this.parse(onRejected(this.value), resolve, reject)
}
})
}
if (this.status === MK.FULFILLED) {
setTimeout(() => {
this.parse(onFulfilled(this.value), resolve, reject)
})
}
if (this.status === MK.REJECTED) {
setTimeout(() => {
this.parse(onRejected(this.value), resolve, reject)
})
}
})
}
parse(result, resolve, reject) {
try {
if (result instanceof MK) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch (error) {
reject(error)
}
}
返回约束
then的返回的promise不能是then相同的Promise,下面是原生Promise的示例将产生错误
const p = new Promise(resolve => {
resolve('mkimq')
})
const p2 = p.then(v => {
return p2
})
解决上面的问题来完善代码,添加当前promise做为parse的第一个参数与函数结果比对
then(onFulfilled, onRejected) {
if (typeof onFulfilled !== 'function') {
onFulfilled = value => value
}
if (typeof onRejected != 'function') {
onRejected = value => value
}
const promise = new MK((resolve, reject) => {
if (this.status === MK.PENDING) {
this.callbacks.push({
onFulfilled: value => {
this.parse(promise, onFulfilled(this.value), resolve, reject)
},
onRejected: value => {
this.parse(promise, onRejected(this.value), resolve, reject)
}
})
}
if (this.status === MK.FULFILLED) {
setTimeout(() => {
this.parse(promise, onFulfilled(this.value), resolve, reject)
})
}
if (this.status === MK.REJECTED) {
setTimeout(() => {
this.parse(promise, onRejected(this.value), resolve, reject)
})
}
})
return promise
}
parse(promise, result, resolve, reject) {
if (promise == result) {
throw new TypeError('Chaining cycle detected for promise')
}
try {
if (result instanceof MK) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch (error) {
reject(error)
}
}
RESOLVE
实现Promise的resolve方法
static resolve(value) {
return new MK((resolve, reject) => {
if (value instanceof MK) {
value.then(resolve, reject)
} else {
resolve(value)
}
})
}
REJEDCT
定义Promise的rejecte方法
static reject(value) {
return new MK((_, reject) => {
reject(value)
})
}
ALL
实现Promise的all方法
static all(promises) {
const resolves = []
return new MK((resolve, reject) => {
promises.forEach((promise, index) => {
promise.then(
value => {
resolves.push(value)
if (resolves.length === promises.length) {
resolve(resolves)
}
},
reason => {
reject(reason)
}
)
})
})
}
RACE
实现Promise的race方法
static race(promises) {
return new MK((resolve, reject) => {
promises.forEach(promise => {
promise.then(value => {
resolve(value)
})
})
})
}
代码详情
class MK {
static PENDING = 'pending'
static FULFILLED = 'fulfilled'
static REJECTED = 'rejected'
constructor(executor) {
this.status = MK.PENDING
this.value = null
this.callbacks = []
try {
executor(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject(error)
}
}
static resolve(value) {
return new MK((resolve, reject) => {
if (value instanceof MK) {
value.then(resolve, reject)
} else {
resolve(value)
}
})
}
static reject(value) {
return new MK((_, reject) => {
reject(value)
})
}
static all(promises) {
const resolves = []
return new MK((resolve, reject) => {
promises.forEach((promise, index) => {
promise.then(
value => {
resolves.push(value)
if (resolves.length === promises.length) {
resolve(resolves)
}
},
reason => {
reject(reason)
}
)
})
})
}
static race(promises) {
return new MK((resolve, reject) => {
promises.forEach(promise => {
promise.then(value => {
resolve(value)
})
})
})
}
then(onFulfilled, onRejected) {
if (typeof onFulfilled !== 'function') {
onFulfilled = value => value
}
if (typeof onRejected != 'function') {
onRejected = value => value
}
const promise = new MK((resolve, reject) => {
if (this.status === MK.PENDING) {
this.callbacks.push({
onFulfilled: value => {
this.parse(promise, onFulfilled(this.value), resolve, reject)
},
onRejected: value => {
this.parse(promise, onRejected(this.value), resolve, reject)
}
})
}
if (this.status === MK.FULFILLED) {
setTimeout(() => {
this.parse(promise, onFulfilled(this.value), resolve, reject)
})
}
if (this.status === MK.REJECTED) {
setTimeout(() => {
this.parse(promise, onRejected(this.value), resolve, reject)
})
}
})
return promise
}
parse(promise, result, resolve, reject) {
if (promise == result) {
throw new TypeError('Chaining cycle detected for promise')
}
try {
if (result instanceof MK) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch (error) {
reject(error)
}
}
resolve(value) {
if (this.status === MK.PENDING) {
this.status = MK.FULFILLED
this.value = value
setTimeout(() => {
this.callbacks.map(callback => {
callback.onFulfilled(value)
})
})
}
}
reject(value) {
if (this.status === MK.PENDING) {
this.status = MK.REJECTED
this.value = value
setTimeout(() => {
this.callbacks.map(callback => {
callback.onRejected(value)
})
})
}
}
}