一、Promise基本实现
1、promise是一个类,无需考虑兼容性
2、当使用promise的时候,会传入一个执行器,此执行器是立刻执行
3、当前excutor 给了两个函数可以来描述当前promise的状态,promise中有三个状态成功态,失败态,等待态
默认为等待态,如果调用resolve会走到成功态,如果调用reject或者发生异常,会走向失败态
4、每个promise实例都有一个then方法
5、promise 一旦状态变化后不能更改
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
class Promise {
constructor(executor) {
this.status = PENDING
this.value = undefined
this.reason = undefined
const resolve = (value) => {
if (this.status === PENDING) {
this.value = value
this.status = FULFILLED
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.reason = reason
this.status = REJECTED
}
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
}
if (this.status === REJECTED) {
onRejected(this.reason)
}
}
}
module.exports = Promise
二、Promise链式调用
当用户调用then方法的时候,此时promise可能为等待态,先暂存起来,因为后续可能会调用resolve和reject,等会再触发对应onFulfilled或者onRejected
1、promise的链式调用:当调用then方法后会返回一个新的promise
情况1:then中方法放回的是一个(普通值,不是promise)的情况,会作为外层下一次then的成功结果
情况2:then中方法执行出错,会走到外层下一次then的失败结果
情况3:如果then中方法返回的是一个promise对象,此时会根据promise的结果来处理是走成功还是失败(传入的是成功或者是失败的内容)
tip:无论上一次then走的是成功还是失败,只要返回的是普通值,都会执行下一次then的成功
总结:如果返回一个普通值(除了promise)就会传递给下一个then的成功,如果返回一个失败的promise或者抛出异常,会走下一个then的失败
2、then处理核心resolvePromise()
1、判断x是否和promise2相同,防止循环调用等待
let promise2 = new Promise((resolve, reject) => {
resolve(1)
}).then(() => {
return promise2
})
2、判断x是否为对象或者函数:
2.1不是,说明x为普通值,直接将他放到promise2.resolve中
2.2是,取出then=x.then,有可能then方法是通过defineProperty实现的,取值时可能发生异常
2.2.1判断then类型是否为function:
是:说明是promise,执行then.call(x)(x.then这样写可能会触发getter,可能会发生异常)
let p = {}
let index = 0
Object.defineProperties(p, 'then', {
get() {
if (++index == 2) throw new Error
}
})
p.then
p.then
否:说明可能为{}、{then:{}},直接resolve(x)
2.3设置caller防止其他人写的promise在调用后也发生异常
2.4处理then穿透问题
new Promise((resolve) => {
resolve(200)
}).then().then().then().then((data) => {
console.log(data, 's')
}, err => {
console.log(err, 'e')
})
//console结果 200s
then(onFulfilled, onRejected)应该为可选参数,如果未使用,应该将参数继续传递下去
处理方法:如果then中的onFulfilled和onRejected不是一个function,需要被忽略,直接返回值即可
onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : v => v
onRejected = typeof onRejected == 'function' ? onRejected : err => { throw err }
const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
const REJECTED = 'REJECTED'
//利用x的值来判断是调用promise2的resolve还是reject
function resolvePromise(promise2, x, resolve, reject) {
//核心流程
if (promise2 === x) {
return reject(new TypeError('错误'))
}
//考虑和其他人写的promise兼容
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
let called = false
try { //then()可能由defineProperty实现,可能发生异常
let then = x.then
if (typeof then === 'function') {
//为promise,x.then 可能触发getter引起异常
then.call(x, y => {
if (called) return
called = true
resolvePromise(promise2, y, resolve, reject)
}, r => {
if (called) return
called = true
reject(r)
})
} else { //{} {then:{}}
resolve(x)
}
} catch (e) {
if (called) return
called = true
reject(e)
}
} else {
resolve(x) //说明返回的是一个普通值,直接放到promise2.resolve中
}
}
class Promise {
constructor(executor) {
this.status = PENDING
this.value = undefined
this.reason = undefined
this.onResolvedCallbacks = [] //成功回调方法
this.onRejectedCallbacks = [] //失败回调方法
const resolve = (value) => {
if (this.status === PENDING) {
this.value = value
this.status = FULFILLED //修改状态
this.onResolvedCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.reason = reason
this.status = REJECTED
this.onRejectedCallbacks.forEach(fn => fn())
}
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
//用于实现链式调用
let promise2 = new Promise((resolve, reject) => {
if (this.status === FULFILLED) {//成功调用成功方法
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}
if (this.status === REJECTED) {//失败调用失败方法
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}
if (this.status === PENDING) { //代码是异步调用resolve或者reject
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
// to do...
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
//to do...
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
})
}
})
return promise2
}
}
module.exports = Promise