promise A+ 规范
术语
- promise是一个有then方法的对象或者函数,行为遵循promiseA+规范
- thanable 是一个有then方法的对象或者函数
- value 是 promise 状态成功的值,也就是resolve的参数,包括各种数据类型, 或者是一个promise
- reason 是 promise 状态失败时的值, 也就是rejected的参数,表示拒绝的原因
- exception throw 抛出去的异常
规范
Promise status
promise 有三种状态,要注意他们之间的流转关系
-
pending
- 初始的状态
- 一个promise在被resolve之前或者rejected之前,都处于这个状态
- 可以通过 resolve -> fullfilled
- 可以通过 reject -> rejected
-
fullfilled
- 最终态,不可该改变
- 一个promise经过resolve之后变成这个状态,必须拥有一个value值 resolve() 相当于 resolve(undefined)
-
rejected
- 最终态,不可该改变
- 一个promise经过reject之后变成这个状态
- 必须拥有一个value值
then
promise 应该提供一个then方法,用来访问最终的结果,无论是value还是reason
promise.then(onFullfilled, onReject)
- 参数要求
onFullfilled, onReject 必须是函数类型,如果不是函数,应该被忽略
-
onFullfilled 特性
- 在promise变成fullfilled时,应该调用哦那onFullfilled, 参数被调用
- 在fullfilled之前,不应该被调用
- 只能被调用一次
-
onRejected特性
- 在promise变成rejected时,应该调用哦那onRejected, 参数被调用
- 在rejected之前,不应该被调用
- 只能被调用一次
-
onFullfilled 和 onRejected 应该是微任务
queuecrotask实现微任务的调用
-
then方法可以被调用多次
-
promise 变成 fullfilled之后,所有onFullfilled的回调都应该按照then的顺序执行
const promise = new Promise(); promise.then(); promise.then(); -
在实现promise的时候需要一个数组来存储 onFullfilled 的回调
-
promise 变成 rejected之后,所有 onRejected 的回调都应该按照then的顺序执行, 也需要一个数组来存储它的回调
-
-
返回值
promise2 = promise.then(onFullfilled, onRejected)- then 的返回值是一个promise
- onFullfilled 和 onRejected 执行结果为x, 调用resolvePromise
- 如果onFullfilled 和 onRejected 执行异常, promise2需要被reject
- 如果 onFullfilled 不是一个函数,promise2就会以 promise1的value 触发 fulfilled
- 如果 onRejected 不是一个函数,promise2就会以 promise1的 reason 触发 rejected
-
resolvePromise
resolvePromise(promise2, x, resolve, reject)-
如果 promise2 与 x 相等,那么 reject TypeError
-
如果 x 是一个promise
- 如果x是pending, promise的状态 直到 x 变成了fulfilled / rejected
- 如果x 是 fulfilled, fulfill promise with same value
- 如果x 是 rejected, reject promise with same reason
-
如果 x 是一个object或者是一个function
let then = x.then
如果x.then这一步出错了, reject(e)
如果 then 是一个函数, then.call(x, resolvePromiseFn, rejectPromiseFn)
resovlePromiseFn的入参是 y ,执行 resolvePromise(promise2, y, resolve, reject)
如果调用 then 的时候抛出了异常,reject reason
-
-
实现一个 promise
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected'
class LPromise {
FULFILLED_CALLBACK_LIST = [];
REJECTED_CALLBACK_LIST = [];
_status = PENDING;
constructor (fn) {
this.status = PENDING;
this.value = null;
this.reason = null;
try {
fn(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject(error);
}
}
get status () {
return this._status;
}
set status (newStatus) {
this._status = newStatus;
switch (newStatus) {
case FULFILLED: {
this.FULFILLED_CALLBACK_LIST.forEach(fn => {
fn(this.value);
});
break;
}
case REJECTED: {
this.REJECTED_CALLBACK_LIST.forEach(fn => {
fn(this.reason);
});
break;
}
}
}
resolve (value) {
if (this.status === PENDING) {
this.value = value;
this.status = FULFILLED;
}
}
reject (reason) {
if (this.status === PENDING) {
this.reason = reason;
this.status = REJECTED;
}
}
// 返回值是一个 promise
then (onFulfilled, onRejected) {
const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : value => value;
const realOnRejected = this.isFunction(onRejected) ? onRejected : reason => { throw reason };
const promise = new LPromise((resolve, reject) => {
const fulfilledMicrotask = () => {
queueMicrotask(() => {
try {
const x = realOnFulfilled(this.value);
this.resovlePromise(promise, x, resolve, reject)
} catch (error) {
reject(error);
}
})
}
const rejectedMicrotask = () => {
queueMicrotask(() => {
try {
const x = realOnRejected(this.reason)
this.resovlePromise(promise, x, resolve, reject)
} catch (error) {
reject(error);
}
})
}
switch (this.status) {
case FULFILLED: {
fulfilledMicrotask()
break;
}
case REJECTED: {
rejectedMicrotask();
break;
}
case PENDING: {
this.FULFILLED_CALLBACK_LIST.push(realOnFulfilled)
this.REJECTED_CALLBACK_LIST.push(realOnRejected)
}
}
});
return promise;
}
catch (onRejected) {
this.then(null, onRejected)
}
resovlePromise (promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('the promise and return value are the same'));
}
// 如果 x 是 promise
if (x instanceof LPromise) {
queueMicrotask(() => {
x.then((y) => {
this.resovlePromise(promise2, y, resolve, reject);
}, reject)
})
} else if (typeof x === 'object' || this.isFunction(x)) {
if (x === null) {
return resolve(x);
}
let then = null;
try {
then = x.then;
} catch (error) {
return reject(error)
}
if (this.isFunction(then)) {
let called = false;
try {
then.call(
x,
y => {
if (called) return
called = true;
this.resovlePromise(promise2, y, resolve, reject)
},
y => {
if (called) return
called = true;
reject(y);
}
)
} catch (error) {
if (called) return
reject(error)
}
} else {
resolve(x)
}
} else {
resolve(x)
}
}
isFunction (value) {
return typeof value === 'function';
}
static resolve (value) {
if (value instanceof LPromise) {
return value;
}
return new LPromise (r => r(value))
}
static resolve (reason) {
if (value instanceof LPromise) {
return value;
}
return new LPromise ((r, j) => j(reason))
}
}
const promise = new LPromise((r, j) => {
r(111)
})
promise.then(e => {
console.log(e);
return e;
}).then(e => {
console.log(e);
return e;
})