promiseA+
术语
1、 promise 是一个有then方法的对象或者函数,行为遵循promiseA+规范
2、thenable 是一个有then方法的对象或者函数
3、value 是promise 状态成功的值 resolve的参数 包括各种数据类型 undefined / number / boolean / promise
4、reason 是promise 状态失败的值 reject的参数 表示拒绝的原因
5、exception throw 抛出去的异常
规范
promise的状态 states
promise 有三种状态,注意状态流转关系
resolve、reject是动作 pending、fulfilled、rejected是状态 fulfilled、rejected动作的结果
pending —> resolve(value) —> fulfilled
pending —> reject(reason) —> rejected
pending
1、初始的状态,可改变
2、promise在被resolve 或者 reject之前,都处于pending状态
3、通过resolve —> fulfilled
4、通过 reject —> rejected
fulfilled
1、最终态,不可改变
2、promise经过resolve后变成fulfilled状态
3、必须拥有一个value值 // undefined
rejected
1、最终态,不可改变
2、promise经过reject后变成rejected状态
3、必须拥有一个reason值 // undefined
then
promise 应该提供一个then方法 用来访问最终结果 无论是value还是reason
promise.then(onFulfilled, onRejected)
参数要求
1、onFulfilled、onRejected必须是函数,不是函数应该被忽略
2、onFulfilled 特性
- promise变成fulfilled时 应该调用onFulfilled 参数是value
- 变成fulfilled之前不应该被调用
- 只能调用一次 (用一个变量限制执行次数)
3、onRejected 特性
- promise变成jejected时 应该调用 onRejected 参数是reason
- promise变成rejected之前不应该被调用
- 只能调用一次(用一个变量限制执行次数)
4、onFulfilled 和 onRejected 应该是微任务
注:有使用setTimeout模拟的,但是setTimeout是金典的宏任务 不是微任务 可以使用 queueMicrotask 实现微任务调用
5、then 方法可以被调用多次
- promise 变成 fulfilled 后, 所有 onFulfilled 的回调都应该按照then的顺序执行。实现promise的时候 需要一个数组来存储 onFulfilled 的 callback
- promise 变成 rejected 后, 所有 onRejected 的回调都应该按照then的顺序执行。实现promise的时候 需要一个数组来存储 onRejected 的 callback
6、then 的返回值是一个 promise
promise2 = promise1.then(onFulfilled, onRejected)
-
onFulfilled, onRejected 执行的结果为 x, 调用resolvePromise
-
onFulfilled, onRejected 执行时抛出异常, promise2 需要被 reject
-
如果 onFulfilled 不是一个函数, promise2 以 promise1的 value 触发 fulfilled
-
如果onRejected 不是一个函数,promise2 以 promise1的 reason 触发 rejected
问:then 返回的是一个新的 promise 还是旧的 promise (新)
7、resolvePromise
resolvePromise(promise2, x, resolve, reject)
- 如果promise2 和 x 相等 那么 reject TypeError
- 如果 x 是一个 promise
- 如果 x 是 pending, promise的状态也必须是 pending,直到x变成 fulfilled / rejected
- 如果 x 是 fulfilled, fulfill promise with then same value
- 如果 x 是 rejected,reject promise with then same reason
- 如果 x 是一个 Object 或者 function
- let then = x.then
- 如果 x.then 这一步出错, try catch(e), reject(e)
- 如果 then 是一个函数, then.call(x, resolvePromiseFn, rejectPromiseFn)
- resolvePromiseFn 的入参是 y, 执行 resolvePromise(promise2, y, resolve, reject)
- 如果调用then抛出了异常, resolvePromiseFn, rejectPromiseFn执行完了就不管了,如果没有被调用 直接 reject reason
手写promise
const PENDING = 'pending'
const FULFILLEF = 'fulfilled'
const REJECTED = 'rejected'
class MPromise {
FULFILLED_CALLBACK_LIST = []
REJECTED_CALLBACK_LIST = []
_status = PENDING
/**
* @param {Function} fn (resolve, reject)
*/
constructor (fn) {
// 初始状态为pending
this.status = PENDING
this.value = null
this.reason = null
try {
fn(this.resolve.bind(this), this.reject,bind(this)) // 用bind 防止传进来的函数不是箭头函数
} catch (e) {
this.reject(e)
}
}
get status () {
return this._status
}
set ststus (newStatus) {
this._status = newStatus
switch (newStatus) {
case FULFILLED:
this.FULFILLED_CALLBACK_LIST.forEach(callback => {
callback(this.value)
})
break
case REJECTED:
this.REJECTED_CALLBACK_LIST.forEach(callback => {
callback(this.reason)
})
break
}
}
resolve (value) {
// 判断状态 只有pending状态才能变成fulfilled
if (this.status === PENDING ) {
this.value = value
this.status = FULFILLEF
}
}
reject (reason) {
// 判断状态 只有pending状态才能变成 rejected
if (this.status === PENDING ) {
this.reason = reason
this.status = REJECTED
}
}
then (onFulfilled, onRejected) {
//6.3、如果 onFulfilled 不是一个函数, promise2 以 promise1 的 value 触发 fulfilled
const realOnFulfilled = this.isFunctin(onFulfilled) ? onFulfilled : (value) => { return value }
//6.4 、如果onRejected 不是一个函数,promise2 以 promise1 的 reason 触发 rejected
const realOnRejected = this.isFunctin(onRejected) ? onRejected : (reason) => { throw reason }
// then 的返回值整体是一个promise
const promise2 = new MPromise((resolve, reject) => {
// 6.2、onFulfilled, onRejected 执行时抛出异常, promise2 需要被 reject
const fulfilledMicrotask = () => {
// 6.1、onFulfilled, onRejected 执行的结果为 x, 调用 resolvePromise
queueMicrotask(() => { // 微任务
try {
let x = realOnFulfilled(this.value)
this.resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
const rejectefMicrotask = () => {
// 6.1、onFulfilled, onRejected 执行的结果为 x, 调用 resolvePromise
queueMicrotask(() => { // 微任务
try {
let x = realOnRejected(this.value)
this.resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
//当调用then的时候 不同状态 调用不同函数
switch (this.status) {
case PENDING:
this.FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask)
this.REJECTED_CALLBACK_LIST.push(rejectefMicrotask)
break
case FULFILLED:
fulfilledMicrotask()
break
case REJECTER:
rejectefMicrotask()
break
}
})
return promise2
}
catch (onRejected) {
return this.then(null, onRejected)
}
resolvePromise (promise2, x, resolve, reject) {
// 7.1、如果promise2 和 x 相等 那么 reject TypeError
if (promise2 === x) {
return reject(new TypeError('The promise and then return value are then same'))
}
if (x instanceof MPromise) {
// 如果 x 是一个 promise 让新的promise接收x状态 即继续执行 x , 如果执行的时候拿到一个y, 那么继续解析y
queueMicrotask(() => { // 微任务
x.then(y => {
this.resolvePromise(promise2, y, resolve, reject)
}, reject)
})
} else if (typeof x === 'object' || this.isFunctin(x)) {
if (x === null) {
return resolve(x)
}
let then = null
try { // 取x.then 赋值给then
then = x.then
} catch (e) {
return reject(e)
}
// 如果获取到的then是一个函数
if (this.isFunctin(then)) {
let called = false
try {
then.call(
x,
(y) => {
if (called) {
return
}
called = true
this.resolvePromise(promise2, y, resolve, reject)
}, // onFulfilled
(r) => {
if (called) {
return
}
called = true
reject(r)
} // onRejected
)
} catch (e) {
if (called) {
return
}
reject(e)
}
} else {
resolve(x)
}
} else {
resolve(x)
}
}
isFunctin (value) {
return typeof value === 'function'
}
static resolve (value) { // 静态方法 不用new就可以调用 使用:MPromise.resolve()
if (value instanceof MPromise) { // value 是个promise 直接返回
return value
}
return new MPromise((resolve) => { // value 不是promise 包装成一个 promise 返回
resolve(value)
})
}
static reject (reason) { // 静态方法
return new MPromise((resolve, reject) => {
reject(reason)
})
}
static race (promiseList) {
return new MPromise((resolve, reject) => {
if (promiseList.length === 0) {
return resolve()
} else {
for (let i = 0; i < promiseList.length; i++) {
MPromise.resolve(promiseList[i]).then(
(value) => { return resolve(value) },
(reason) => { return reject(reason) }
)
}
}
})
}
}
测试
const test = new MPromise((resolve, reject) => {
setTimeOut(() => {
resolve(111)
}, 1000)
}).then((value) => {
console.log('then')
})
setTimeout(() => {
// 问:value 是什么 答:undefined 状态是fulfilled 原因: then调用没有return(无返回值),默认 return undefined
console.log(test)
}, 3000)
问:链式调用每次调用返回一个新的promise 为什么 then() 中 pending状态时候 要使用数组来存? 答:promise 可以多次同一实例调用
调用方式一:
new MPromise((resolve, reject) => {}).then(() => {}).then(() => {}).then(() => {})
调用方式二:
const test = new MPromise((resolve, reject) => {})
test.then(() => {})
test.then(() => {})
test.then(() => {})
const test = new MPromise((resolve, reject) => {
setTimeOut(() => {
resolve(111)
}, 1000)
}).catch((reason) => {
console.log('报错' + reason)
// 问 test status 的状态是什么 答:pending
// 原因:打印promise的时候,整个回调并没执行完成 只有当整个回调完成后才能更改状态
console.log(test)
})
setTimeOut(() => {
// 问 test status 的状态是什么 答:fulfilled
// 原因: catch 函数会返回一个新的promise, 成功执行完成,新的promise 的状态会变成fulfilled
console.log(test)
}, 3000)
// 1、catch 函数会返回一个新的promise, 而且test就是这个新的promise
// 2、catch 回调里 打印promise的时候,整个回调并没执行完成 只有当整个回调完成后才能更改状态
// 3、catch 回调函数,如果成功执行完成,那么新的promise 的状态会变成fulfilled