一、什么是promise?
- promise是一个有then方法的对象或者是函数,行为遵循本规范;
- thenable是一个有then方法的对象或者是函数;
- value是promise状态成功时的值,也就是resolve的参数,包括各种数据类型,也包括undefined/thenable或者是promise;
- reason是promise状态失败时的值,也就是reject的参数,表示拒绝的原因;
- exception是一个使用throw抛出的异常值。
二、A+规范
1、promise的三种状态
-
pending
1.1 初始的状态,可改变;
1.2 一个promise在resolve或者reject前都处于这个状态;
1.3 可以通过resolve->fulfilled状态;
1.4 可以通过reject->rejected状态;
-
fulfilled
1.1 最终态,不可变;
1.2 一个promise被resolve后会变成这个状态;
1.3 必须拥有一个value值
-
rejected
1.1 最终态,不可变;
1.2 一个promise被reject后是这个状态;
1.3 必须拥有一个reason
2、promise的状态流转
- pending->resolve(value)->fulfilled
- pending->reject(reason)->rejected
三、then
promise有一个then方法,用来访问最终的结果,无论是value还是reason。
promise.then(onFunfilled,onRejected)
1、两个参数:
1.1 onFulfilled必须是函数类型,如果不是函数,应该被忽略;
- 在promise变成fulfilled时,应该调用onFulfilled,参数是value;
- 在promise变成fulfilled之前,不应该被调用;
- 只能被调用一次(所以在实现的时候需要一个变量来限制执行次数) 1.2 onRejected必须是函数类型,如果不是函数,应该被忽略;
- 在promise变成rejected时,应该调用onRejected,参数是reason;
- 在promise变成rejected之前,不应该被调用;
- 只能被调用一次(所以在实现的时候需要一个变量来限制执行次数)
2、onFulfilled和onRejected是微任务
使用queueMicrotask来实现微任务的调用。
3、then方法可以被调用多次
3.1 promise状态变成fulfilled后,所有的onFulfilled回调都需要按照then的顺序执行,也就是按照注册顺序执行(所以在实现的时候需要一个数组来存放多个onFulfilled的回调);
3.2 promise的状态变成rejected后,所有的onRejected回调都需要按照then的顺序执行,也就是按照注册顺序执行(所以在实现的时候需要一个数组来存放多个onRejected的回调)
4、then方法的返回值
4.1 then返回的是一个全新的promise
promise2 - promise1.then(onFulfilled, onRejected);
4.2 设onFulfilled或者onRejected执行的结果为x,调用resolvePromise(后面解释);
4.3 如果onFulfilled或者onRejected执行时抛出异常e,promise2需要被reject;
4.4 如果onFulfilled不是一个函数,promise2以promise1的value触发fulfilled;
4.5 如果onRejected不是一个函数,promise2以promise1的reason触发rejected;
5、重点解释下resolvePromise
// 用来分类处理返回值
resolvePromise(promise2, x, resolve, reject)
5.1 如果promise2和x相等,那么reject TypeError;
5.2 如果x是一个promise,则使newPromise接受x的状态;继续执行x,如果执行的时候拿到一个y,还要继续解析y;
5.3 如果x是一个object或者是一个function,
let then = x.then; //try catch包一下
如果是一个函数,
then.call(x, resolvePromiseFn, rejectPromise);
resolvePromiseFn的入参是y,执行resolvePromise(promise2, y,resolve, reject);
如果不是一个函数,则直接resolve(x)
四、代码实现
// status的三种状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
\
class MPromise {
// 一个细节考察点
// 用数组来存回调函数,不适用于链式调用.then中,因为每一个.then返回的都是一个新的promise,
// 当调用的promise实例是同一个的时候,数组就有意义了
FULFILLED_CALLBACK_LIST = [];
REJECTED_CALLBACK_LIST = [];
// status的状态需要监听值的变化,实用getter\setter
_status = PENDING;
constructor(fn) {
// 初始状态为pending
this.status = PENDING;
// 成功的初始值
this.value = null;
// 失败的初始值
this.reason = null;
try {
fn(this.resolve.bind(this), this.reject.bind(this));
} catch (e) {
this.reject(e);
}
}
\
// 获取status的值
get status() {
return this._status;
}
// status值发生变化
set status(newStatus) {
this._status = newStatus;
switch (newStatus) {
case FULFILLED: {
this.FULFILLED_CALLBACK_LIST.forEach(callback => {
callback(this.value);
});
break;
}
case REFUSED: {
this.REJECTED_CALLBACK_LIST.forEach(callback => {
callback(this.reason)
});
break;
}
}
}
\
resolve(value) {
// 只有状态为pending的前提下,值和状态才能变成成功或是失败
if (this.status === PENDING) {
this.value = value;
this.status = FULFILLED;
}
}
\
reject(reason) {
if (this.status === PENDING) {
this.reason = reason;
this.status = REJECTED;
}
}
\
// then方法
then(onFulfilled, onRejected) {
const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => {
return value
}
const realOnRejected = this.isFunction(onRejected) ? onRejected : (reason) => {
throw reason
}
// then方法返回的是一个新的promise2
// onFulfilled和onRejected是微任务,使用queueMicrotask来实现微任务的调用
const promise2 = new MPromise((resolve, reject) => {
// 成功
const fulfilledMicrotask = () => {
queueMicrotask(() => {
try {
const x = realOnFulfilled(this.value);
// 调用此方法来分类处理x得到的值
this.resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e);
}
})
};
// 失败
const rejectedMocrotask = () => {
queueMicrotask(() => {
try {
const x = realOnFulfilled(this.reason);
// 分类处理
this.resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
\
// 根据状态来调用方法
switch (this.status) {
case FULFILLED: {
fulfilledMicrotask()
break;
}
case REJECTED: {
rejectedMocrotask()
break;
}
case PENDING: {
this.FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask);
this.REJECTED_CALLBACK_LIST.push(rejectedMocrotask);
}
}
})
return promise2;
}
\
catch(onRejected) {
return this.then(null, onRejected)
}
\
// 判断参数是否是函数
isFunction(param) {
return typeof parame === 'function';
}
\
// 分类处理then的返回值
resolvePromise(promise2, x, resolve, reject) {
// 如果newPromise和x指向同一个对象,以typeerror拒绝执行newPromise
// 这是为了防止死循环
if (promise2 === x) {
return reject(new TypeError('the promise and the return value are the same'))
}
\
// 如果x是promise
if (x instanceof MPromise) {
// 如果x为promise,则继续执行x,如果执行的结果是y,需要继续判断y
queueMicrotask(() => {
x.then((y) => {
this.resolvePromise(promise2, y, resolve, reject)
}, reject)
})
} else if (typeof x === 'object' || this.isFunction(x)) {
// 如果x为对象或者函数
// null也会被判断为对象
if (x === null) {
return resolve(x);
}
\
let then = null;
try {
then = x.then;
} catch (error) {
return reject(error);
}
\
// 如果then是函数
if (this.isFunction(then)) {
let called = false;
// 将x作为函数的作用域this调用
// 传递两个回调函数作为参数,第一个参数是resolvePromise,第二个参数叫做rejectPromise
try {
then.call(
x,
// 如果resolvePromise以值y为参数被调用,则运行resolvePromise
(y) => {
// 需要以一个变量called来保证只调用一次
if (called) return;
called = true;
this.resolvePromise(promise2, y, resolve, reject)
},
// 如果rejectPromise以据因r为参数被调用,则以据因r拒绝promise
(r) => {
if (called) return;
called = true;
reject(r);
}
)
} catch (e) {
if (called) return;
reject(e)
}
} else {
// 如果then不是函数
resolve(x)
}
} else {
// 如果x不为对象或者函数,以x为参数执行promise
resolve(x)
}
}
\
// 静态方法resolve
static resolve(value) {
if (value instanceof MPromise) {
return value;
}
\
return new MPromise((resolve) => {
resolve(value);
})
}
\
// 静态方法 reject
static reject(reason) {
return new MPromise((resolve, reject) => {
reject(reason);
})
}
\
// 静态方法 race,竞赛,一个先完成就结束
static race(promiseList) {
return new MPromise((resolve, reject) => {
const length = promiseList.length;
if (length === 0) {
return resolve();
} else {
for (let i = 0; i < length; i++) {
MPromise.resolve(promiseList).then(
(value) => {
return resolve(value);
},
(reason) => {
return reject(reason);
}
)
}
}
})
}
\
// 静态方法 all ,等到所有的promise都执行完
static all(promiseList) {
let index = 0;
let result = [];
return new MPromise((resolve, reject) => {
promiseList.forEach((p, i) => {
// 使用MPromise.resolve(p)用于处理传入值不为promise的情况
MPromise.resolve(p).then(
value => {
index++;
result[i] = value;
if (index === promiseList.length) {
resolve(result)
}
},
reason => {
reject(reason)
}
)
})
})
}
}
\
// 写一个简单的测试用例
const test = new MPromise((resolve, reject) => {
setTimeout(() => {
reject(111);
}, 1000);
}).then((value) => {
console.log('then');
}).catch((reason) => {
console.log('catch');
})
\