promiseA+规范
常见术语
1) promise: 一个有then方法的对象或者函数,它的行为遵从promiseA+规范
2) thenable: 一个有then方法的对象或者函数
3) value: promise执行成功时候的值,也是resolve的参数,可以是任意数据类型
4) reason: promise执行失败时候的值,也是reject的参数
5) exception: throw 抛出来的异常
promise status 状态流转
promise 有三种状态:可以实现状态之间的流转。
1) pending 状态 初始状态 可变
可以通过resolve变成fulfilled状态
可以通过reject变成rejected状态
2) fulfilled 执行成功时候的状态 最终状态 不可变
通过resolve变成fulfilled状态
必须有一个value值
3) reject 执行失败时候的状态
通过reject变成rejected状态
必须有一个reason值
then promise应该提供一个then方法,用来访问最后的结果
promise.then(onFulfilled, onRejected)
1.onFulfilled和onRejected必须是函数,如果不是函数,应该被忽略
2.onFulfilled和onRejected必须是微任务 使用queueMicrotask
3.onFulfilled和onRejected都只能被调用一次,当promise的状态变成fulfilled的时候,应该调用
onFulfilled,当promise的状态变成rejected的时候,应该调用onRejected。
4.then方法可以被调用多次,当promise状态变成fulfilled后,所有的onFulfilled回调都需要按照
then的顺序执行,也就是按照注册的顺序执行。当promise状态变成rejected后,所有的onRejected回调
都需要按照then的顺序执行,也就是按照注册的顺序执行。
5.then 方法的返回值是一个新的promise
6.resolvePromise
resolvePromise(promise2, x, resolve, reject)
6.1 如果x和prommise2相等 则抛出异常,避免死循环
6.2 如果x是一个promise 递归调用resolvePromise
6.3 如果x是一个object或者是一个function
let then = x.then
如果x.then出错,那么 reject 出去
then是一个函数 则 then.call(x, resolvePromiseFn, rejectPromise)
如果then不是一个函数 则直接resolve出去
基于promiseA+规范实现一个简易版本promise
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MPromise {
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 (err) {
this.reject(err);
}
}
get status () {
return this._status;
}
set status (newStatus) {
this._status = newStatus;
switch (this._status) {
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) {
if (this.status !== PENDING) {
return;
}
this.value = value;
this.status = FULFILLED;
}
reject (reason) {
if (this.status !== PENDING) {
return;
}
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 MPromise((resolve, reject) => {
const fulfilledMicroTask = () => {
queueMicrotask(() => {
try {
const x = realOnFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
} catch (err) {
reject(err);
}
});
};
const rejectedMicroTask = () => {
queueMicrotask(() => {
try {
const x = realOnRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
} catch (err) {
reject(err);
}
});
};
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);
break;
}
});
return promise2;
}
resolvePromise (promise2, x, resolve, reject) {
if (x === promise2) {
return reject(TypeError('the x and promise are the same'));
}
if (x instanceof MPromise) {
x.then(y => {
this.resolvePromise(promise2, y, resolve, reject);
}, reject);
}
if (this.isFunction(x) || typeof x === 'object') {
if (x === null) {
return resolve(x);
}
let then = null;
try {
then = x.then;
} catch (err) {
return reject(err);
}
if (this.isFunction(then)) {
let called = false;
then.call(x,
y => {
if (called) {
return;
}
called = true;
this.resolvePromise(promise2, y, resolve, reject);
},
r => {
if (called) {
return;
}
called = true;
reject(r);
}
);
} else {
resolve(x);
}
} else {
resolve(x);
}
}
catch (onRejected) {
return this.then(null, onRejected)
}
static resolve (value) {
if (value instanceof MPromise) {
return value;
}
return new MPromise((resolve, reject) => {
resolve(value);
});
}
static reject (reason) {
return new MPromise((resolve, reject) => {
reject(reason);
});
}
static race (promiseList = []) {
return new MPromise((resolve, reject) => {
const len = promiseList.length;
if (!len) {
return resolve();
}
for (let i = 0; i < len; i++) {
MPromise.resolve(promiseList[i]).then(
value => resolve(value),
reason => reject(reason)
);
}
});
}
和传入的数组的顺序是一样的
static all (promiseList = []) {
return new MPromise((resolve, reject) => {
const len = promiseList.length;
let resolvedNum = 0;
const resolvedValueList = new Array(len);
for (let i = 0; i < len; i++) {
MPromise.resolve(promiseList[i]).then(value => {
resolvedNum++;
resolvedValueList[i] = value;
if (resolvedNum === len) {
resolve(resolvedValueList);
}
}, reason => reject(reason));
}
});
}
isFunction (value) {
return typeof value === 'function';
}
}