promise 规范+简单实现
PromiseA+规范
术语
- Promise是一个有than方法的对象或者函数,行为遵循A+规范
- thenable也是一个有then方法的对象或函数
- value是promise转为fulfiled时的值,也是resolve的参数
- reason是promise转为rejected时的拒因
- exception 是一个使用throw抛出了的异常值
规范如下:
states
promise有三种状态
- pendding 1.1 初始的状态。可以改变 1.2 一个promise在resolve和reject之前都 处于这个状态 1.3 可以 resolve-> fulfilled状态 1.4 可以 reject-> rejected状态
- fulfilled 2.1 最终值 不可变 2.2 通过reaolve 变为fulfilled 2.3 必须有一个value值
- rejected 3.1 最终值, 不可变 3.2 通过reject 变成rejected 3.3 必须有一个reason值
then
promise必须提供一个then方法用来访问最终的结果,value或者reason
promise.then(onFulfilled,onRejected)
- 参数要求 1.1 onFullfilled 必须是一个函数 否则被忽略
realFulfilled = this.isFunction(onFulfilled) ? onFulfilled : value=>value
1.2 onRejected 必须是一个函数 否则被忽略
realRejected = this.isFunction(onRejected) ? onRejected: reason=>{throw new Error('xxx')}
-
onFulfilled 特性 2.1 在状态变为fulfilled时调用 参数是value 2.2 状态改变之前 不应该调用 2.3 只能调用一次
-
onRejected 特性 3.1 在状态变为rejected时调用 参数是reason 3.2 状态改变之前 不应该调用 3.3 只能调用一次
-
onFulfilled和onRejected应该是微任务
-
then方法可以被调用多次 5.1 promise状态变成 fulfilled 后,所有的 onFulfilled 回调都需要按照then的顺序执行, 也就是按照注册顺序执行(所以在实现的时候需要一个数组来存放多个onFulfilled的回调) 5.2 promise状态变成 rejected 后,所有的 onRejected 回调都需要按照then的顺序执行, 也就是按照注册顺序执行(所以在实现的时候需要一个数组来存放多个onRejected的回调)
-
返回值 then方法返回一个promise
promise2 = promise1.then(onFulfilled, onRejected);
```
6.1 onFulfilled或onRejected的结果为x, 调用 resolvePromise
6.2 如果 onFulfilled 或者 onRejected 执行时抛出异常e, promise2需要被reject
6.3 如果 onFulfilled 不是一个函数, promise2 以promise1的value 触发fulfilled 值的透传
```js
new Promise((resolve,reject)=>{
resolve(1)
})
.then(3)
.then(3)
.then(res=>{
console.log(res)
})
// 1
```
6.4 如果 onRejected 不是一个函数, promise2 以promise1的reason 触发rejected 值的透传
7. resolvePromise(promise2,x,resolve,reject)
7.1 r如果promise2 和x相等 则return Error 防止死循环
```js
if(x===promise2) {
reject(new TypeError('xxxx'))
}
```
7.2 如果 x 是一个 promsie
如果x是pending态,那么promise必须要在pending,直到 x 变成 fulfilled or rejected.
如果 x 被 fulfilled, fulfill promise with the same value.
如果 x 被 rejected, reject promise with the same reason.
```js
x.then(
y=>{
this.resolvePromise(promise2,y,resolve,reject)
},
reject
)
```
7.3 如果 x 是一个 object 或者 是一个 function
如果 x.then 这步出错,那么 reject promise with e as the reason
```js
let then
try {
then = x.then
} catch(e) {
reject(e)
}
```
如果 then 是一个函数,then.call(x, resolvePromiseFn, rejectPromise)
resolvePromiseFn 的 入参是 y, 执行 resolvePromise(promise2, y, resolve, reject);
rejectPromise 的 入参是 r, reject promise with r.
如果 resolvePromise 和 rejectPromise 都调用了,那么第一个调用优先,后面的调用忽略。
如果调用then抛出异常e
如果 resolvePromise 或 rejectPromise 已经被调用,那么忽略
则,reject promise with e as the reason
```js
if (this.isFunction(then)) {
let called = false
try {
then.call(
x,
y=>{
if (called) return
called = true
this.resolvePromise(promise2,y,resolve,reject)
},
r=>{
if (called) return
called = true
reject(r)
}
)
} catch(e) {
reject(e)
}
} else {
resolve(x)
}
```
如果 then 不是一个function. fulfill promise with x.
### 完整代码
```js
const PENDDING= 'pendding'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class LPromise {
FULFILLED_CB_LIST= []
REJECTED_CB_LIST = []
constructor (fn) {
this.value = undefined
this.reason = undefined
this.status = PENDDING
try {
fn(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject(error)
}
}
resolve(value) {
if (this.status === PENDDING) {
this.status = FULFILLED
this.value = value
if(this.FULFILLED_CB_LIST.length){
this.FULFILLED_CB_LIST.forEach(cb=>cb(this.value))
}
}
}
reject(reason){
if (this.status === PENDDING){
this.status = REJECTED
this.reason = reason
if(this.REJECTED_CB_LIST.length){
this.REJECTED_CB_LIST.forEach(cb=>cb(this.reason))
}
}
}
then(onFulfilled, onRejected){
const realFulfilled = this.isFunction(onFulfilled) ? onFulfilled : value => value
const realRejected = this.isFunction(onRejected) ? onRejected : reason=>{throw Error(reason)}
const promise2 = new LPromise((resolve,reject)=>{
const fulflledMircotask = ()=>{
queueMicrotask (()=>{
try {
const x = realFulfilled(this.value)
this.resolvePromise(promise2,x,resolve,reject)
} catch (error) {
reject(error)
}
})
}
const rejectedMircotask = ()=>{
queueMicrotask(()=>{
try {
const x = realRejected(this.reason)
this.resolvePromise(promise2,x,resolve,reject)
} catch (error) {
reject(error)
}
})
}
switch (this.status) {
case FULFILLED: {
fulflledMircotask()
break
}
case REJECTED: {
rejectedMircotask()
break
}
case PENDDING:{
this.FULFILLED_CB_LIST.push(fulflledMircotask)
this.REJECTED_CB_LIST.push(rejectedMircotask)
break
}
}
})
return promise2
}
resolvePromise(promise2,x,resolve,reject){
if (promise2 === x) {
return reject(new TypeError('can not return the same value'))
}
if (x instanceof LPromise) {
queueMicrotask(()=>{
x.then(
y=>{
this.resolvePromise(promise2,y,resolve,reject)
},
r=>{
reject(r)
}
)
})
}
if (x === null) {
return resolve(x)
}
if (typeof x === 'object' || this.isFunction(x)) {
let then
try {
then = x.then
if (this.isFunction(then)) {
let used = false
then.call(
x,
y=>{
if(used) return
used = true
this.resolvePromise(promise2,y,resolve,reject)
},
r=>{
if(used) return
used = true
reject(r)
}
)
} else {
resolve(x)
}
} catch (error) {
reject(error)
}
} else {
resolve(x)
}
}
isFunction(fn){
return typeof fn === 'function'
}
}
var p1 = new LPromise((resolve,reject)=>{
resolve('111')
}).then((res)=>{
console.log('res',res)
return 'resolve1111'
},r=>{
console.log('r',r)
return 'reject1111'
}).then(res=>{
console.log('d第二个then的res',res)
})