遵循PromiseA+规范
- promise 是一个有 then 方法的对象或者函数,行为遵循本规范
- thenable 是一个有then 方法的对象或者函数
- value 是 promise 状态成功时的值,也就是 resolve 的参数,包括各种数据类型,也包括undefined / thenable 或者 promise
- reason 是 promise 状态失败时的值,也就是reject的参数,表示拒绝的原因
- exception 是使用 、throw 抛出的异常的值
Promise 应该有三个状态
- pending 状态
- promise 的初始状态,可改变;一个promise 在resolve 和 reject 之前都处于这个状态;可以通过resolve 改为 fulfilled OR 通过 reject 改为 rejected;
- fulfilled 状态
- 最终状态不可改变;一个promise 被resolve 后变成这个状态,必须有一个value 值
- rejected 状态
- 最终状态不可改变;一个promise 被reject 后变成这个状态,必须有一个reason 值
Promise 应该有一个then方法
- promise.then(onFulfilled, onRejected)
tips: onFulfilled, onRejected 必须是函数,只能被调用一次(so 通过一个变量来控制,限制执行次数);在promise变成 fulfilled 时,应该调⽤ onFulfilled, 参数是value; 在promise变成 rejected 时,应该调⽤ onRejected, 参数是reason;在Promise 的状态为pending 的时候不应该被调用
- onFulfilled, onRejected 应该是微任务,so 通过 queueMicrotask 来实现微任务的调用
- then 方法应该返回一个Promise 如:promise2 = promise1.then( onFulfilled, onRejected)
- promise 的状态变为 fulfilled 或者 rejected 的时候,所有的onFulfilled 或者 onRejected 都需要按照then的顺序执行,也就是按照注册的顺序执行,所以我们需要一个数组来存放这行状态函数
以下为手写的Promise
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class APromise {
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 (e) {
this.reject(e)
}
}
get status() {
return this._status
}
set status(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))
}
}
}
resolve(value) {
if(this.status === PENDING) {
this.value = value;
this.status = FULFILLED
}
}
reject(reason){
if(this.status === PENDING) {
this.reason = reason;
this.status = REJECTED;
}
}
then(onFulfilled, onRejected) {
const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : value => value;
const realOnRejected = this.isFunction(onRejected) ? onRejected : reason => { throw reason };
const promise2 = new APromise((resolve, reject) => {
const fulfilledMicrotask = () => {
queueMicrotask(() => {
try {
const x = realOnFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
} catch (e) {
this.reject(e);
}
})
}
const rejectedMicrotask = () => {
queueMicrotask(() => {
try {
const x = realOnRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject)
}catch (e) {
this.reject(e)
}
})
}
switch (this.status) {
case FULFILLED: {
fulfilledMicrotask()
break;
}
case REJECTED: {
rejectedMicrotask()
break;
}
case PENDING: {
this.FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask);
this.REJECTED_CALLBACK_LIST.push(rejectedMicrotask);
}
}
});
return promise2;
}
catch(onRejected) {
this.then(null, onRejected)
}
resolvePromise(promise2, x, resolve, reject ) {
if( promise2 === x) {
return reject(new TypeError('promise2 和 x 不能相同'));
}
if(x instanceof APromise) {
queueMicrotask(() => {
x.then((y) => {
this.resolvePromise(promise2, y, resolve, reject)
}, reject)
})
}
if(typeof x ==='object' || this.isFunction(x)) {
if(x === null ) {
return resolve(x);
}
let then = null;
try {
then = x.then;
}catch (e) {
return reject(e);
}
if(this.isFunction(then)) {
let called = false;
try {
then.call(x, (y) => {
if(called) return;
this.resolvePromise(promise2, y, resolve, reject);
called = true;
}, (r) => {
if(called) return;
called = true;
reject(r)
})
}catch (e) {
if (called) return;
reject(e);
}
}
}else {
resolve(x)
}
}
isFunction(param) {
return typeof param === 'function';
}
}
let my = new APromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 2000)
}).then(console.log).then(() => {
console.log(2)
})