前言
术语
1.promsie 是一个有 then方法的对象或者是函数,行为遵循本规范
2.thenable 是一个有then 方法的对象或者是函数
3.vuale是 promise状态成功时的值, 也就是resolve的参数, 包括各种数据类型,也包括undefined、thenable、或者是promise
4.reason是promise状态失败时的值,也就是reject的参数,表示拒绝的原因
5.exception 是一个使用throw抛出的异常的值
Promise的状态
1.pending
- 初始的状态, 可以改变
- 一个promise 在resolve 或者reject前都处于这个状态
- 可以通过 resolve -> fulfilled状态
- 可以通过reject -> rejected状
2.fulfilled
- 最终态,可以改变
- 一个promise被resolve 后变成这个状态
- 必须要拥有一个value值
3.rejected
- 最终太,不可以改变
- 一个promsie被rejected后会变成这个状态
- 必须要拥有一个reason值
then
promise应该提供一个then方法,用来访问最终的结果,无论是value 还是reason 比如:
promise.then(onFulfilled, onRejected)
1.参数要求
- onFulfilled 必须是函数类型,如果不是函数类型,应该被忽略
- onRejected 必须是函数类型,如果不是函数,应该被忽略
2.onFulfilled 特性
- 在promsie变成fulfilled时,应该调用 onFulfilled,参数是value
- 在promise变成 fulfilled之前,不应该被调用
- 只能被调用一次
3.nRejected 特性
- 在promise变成 rejected 时,应该调用 onRejected, 参数是reason
- 在promise变成 rejected 之前, 不应该被调用.
- 只能被调用一次
4.onFulfilled 和 onRejected 应该是微任务
- 这里用queueMicrotask来实现微任务的调用 queueMicrotask()在mdn查看;
5.then方法可以被调用多次
- promise状态变成 fulfilled 后,所有的 onFulfilled 回调都需要按照then的顺序执行, 也就是按照注册顺序执行
- promise状态变成 rejected 后,所有的 onRejected 回调都需要按照then的顺序执行, 也就是按照注册顺序执行
6.返回值
then 应该返回一个promise
promise2 = promise1.then(onFulfilled, onRejected);
- onFulfilled 或 onRejected 执行的结果为x, 调用 resolvePromise
- 如果 onFulfilled 或者 onRejected 执行时抛出异常e, promise2需要被reject
- 如果 onFulfilled 不是一个函数, promise2 以promise1的value 触发fulfilled
- 如果 onRejected 不是一个函数, promise2 以promise1的reason 触发rejected
7.Promise解析的过程
resolvePromise(promise2, x, resolve, reject)
- 如果promise2 和x相等的时候,那么就要返回出 reject TypeError作为原因将promise拒绝
- 如果 x是一个promise的话
- 如果x是pending状态,那么promise必须保持pending状态,直到x被解决或拒绝
- 如果x是fulfilled状态,那么要用相同的值解决promise
- 如果x是rejected状态,用相同的原因拒绝promise
3.如果 x 是一个 object 或者 是一个 function
- let then = x.then.
- 如果检索属性x.then导致抛出了一个异常e,用e作为原因拒绝promise
- 如果 then 是一个函数,用x作为this调用它。then方法的参数为俩个回调函数,第一个参数叫做resolvePromise,第二个参数叫做rejectPromise
-
resolvePromise用一个值调用 y, 则执行 resolvePromise(promise2, y, resolve, reject);
-
rejectPromise 用一个值调用 r, 用r拒绝promise
-
如果 resolvePromise 和 rejectPromise 都调用了,那么第一个调用优先,后面的调用忽略。
-
如果调用then则抛出异常e
-
如果 resolvePromise 或 rejectPromise 已经被调用,则用e作为原因拒绝promise
-
- 如果x不是一个对象或函数,则 resolve(x)
一步步实现一个简易第Pormise
第一步:首先定义个MyPromise的class类
class MyPromise() {
constructor() {
}
}
第二步: 然后定义promise的三种类型状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
第三步: 然后开始设置初始值的状态
class MyPromise() {
constructor() {
this.status = PENDING;
this.value = null;
this.reason = null;
}
}
第四步: 定义resolve方法 和reject方法
1.2个方法是要更改status的,从pendin改到fulfilled/rejected
2.两个函数的入参分别为value 和reason
class MyPromise() {
constructor() {
this.status = PENDING;
this.value = null;
this.reason = null;
}
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方法
1.then方法接收2个参数,onFufilled 和 onRejected
then(onFufilled,onRejected) {
}
2.检查并处理参数,判断如果不是方法,就忽略,(原样返回value和reason),定一个isFunction方法
isFunction(param) {
return typeof param === 'function';
}
then(onFufilled,onRejected) {
const fufilled_fn = this.isFunction(onFulfilled) ? onFufilled : (value) => {
return value;
}
const rejected_fn = this.isFunction(onRejected) ? onRejected : (reason) => {
throw reason;
}
}
3.根据promise的status,调用不同的方法
isFunction(param) {
return typeof param === 'function';
}
then(onFufilled,onRejected) {
const fufilled_fn = this.isFunction(onFulfilled) ? onFufilled : (value) => {
return value;
}
const rejected_fn = this.isFunction(onRejected) ? onRejected : (reason) => {
throw reason;
}
switch(this.status) {
case FULFILLED: {
this.fufilled_fn(this.value);
break;
}
case REJECTED: {
this.rejected_fn(this.reason);
}
}
}
4.如果then方方法在被调用的瞬间就会执行,那么这个时候status状态还没变成fulfilled和rejected,很有可能status还在处于pending状态,
- 那么就要首先拿到了所有的回调之后,然后才能在某个时候去执行他,
- 这个时候就要新建2个新的数组来存储成功和失败的回调,调用then的时候,如果还是pending状态就分别存入这2个数组
class MyPromise() {
FULFILLED_LIST = [];
REJECTED_LIST = [];
constructor() {
this.status = PENDING;
this.value = null;
this.reason = null;
}
then(onFufilled,onRejected) {
const fufilled_fn = this.isFunction(onFulfilled) ? onFufilled : (value) => {
return value;
}
const rejected_fn = this.isFunction(onRejected) ? onRejected : (reason) => {
throw reason;
}
switch(this.status) {
case FULFILLED: {
this.fufilled_fn(this.value);
break;
}
case REJECTED: {
this.rejected_fn(this.reason);
break;
}
case PENDING: {
this.FULFILLED_LIST.push(fufilled_fn);
this.REJECTED_LIST.push(rejected_fn);
break;
}
}
}
}
4.2 在status发生变化的时候,就执行所有的回调,用es6的getter和setter
class MyPromise() {
FULFILLED_LIST = [];
REJECTED_LIST = [];
_status = PENDING;
constructor() {
this.status = PENDING;
this.value = null;
this.reason = null;
}
get status() {
this._status;
}
set status(newStatus) {
this._status = newStatus;
switch() {
case FULFILLED:{
this.FULFULLED_LIST.forEach(callback => {
callback(this.value);
});
break;
}
case REJECTED:{
this.REJECTED_LIST.forEach(callback => {
callback(this.reason);
});
break;
}
}
}
}
第六步.then的返回值
- 如果onFulfilled 或者 onRejected抛出了一个异常e,则promise 必须拒绝执行,并且返回e
.
then(onFufilled,onRejected) {
const fulFilled_fn = this.isFunction(onFulfilled) ? onFufilled : (value) => {
return value;
}
const rejected_fn = this.isFunction(onRejected) ? onRejected : (reason) => {
throw reason;
}
const fufilledFnCatch = (resolve,reject) => {
try {
fulFilled_fn(this.value);
} catch (e){
reject(e);
}
}
const rejectedFnCatch = (resolve,reject) => {
try {
rejected_fn(this.reason);
} catch (e){
reject(e);
}
}
switch(this.status) {
case FULFILLED: {
retuen new MyPromise(fufilledFnCatch);
}
case REJECTED: {
retuen new MyPromise(rejectedFnCatch);
}
case PENDING: {
return new MyPromise((resovle,reject) => {
this.FULFILLED_LIST.push(fufilledFnCatch(resolve,reject));
this.REJECTED_LIST.push(rejectedFnCatch(resolve,reject));
});
}
}
}
- 如果onFulfilled 不是一个方法且promise1成功执行,promise必须成功执行并返回相同的值
const fuilledFnCatch = (resolve, reject, newPromise) => {
try {
if (!this.isFunction(onFulfilled)) {
resolve(this.value);
}
} catch (e) {
reject(e)
}
};
- 如果 onRejected 不是方法且 promise1拒绝执行, 那么promise2必须拒绝执行并返回相同的值
const rejectedFnCatch = (resolve, reject) => {
try{
if (!this.isFunction(onRejected)) {
reject(this.reason);
}
} catch (e) {
reject(e);
}
}
4.如果 onFulfilled 或 onRejected不是方法,那么promise2必须拒绝执行并返回相同的值,否则返回一个值x,这运行Promise解决程序(resovlePromise方法),请查看规范第7点;
const fulFilledFnCatch = (resolve, reject, newPromise) => {
try {
if (!this.isFunction(onFulfilled)) {
resolve(this.value);
} else {
const x = fulFilled_fn(this.value);
this.resolvePromise(newPromise, x, resolve, reject);
}
} catch (e) {
reject(e)
}
};
const rejectedFnCatch = (resolve, reject, newPromise) => {
try {
if (!this.isFunction(onRejected)) {
reject(this.reason);
} else {
const x = rejected_fn(this.reason);
this.resolvePromise(newPromise, x, resolve, reject);
}
} catch (e) {
reject(e);
}
}
switch (this.status) {
case FULFILLED: {
const newPromise = new MPromise((resolve, reject) => fulFilledFnCatch(resolve, reject, newPromise));
return newPromise;
}
case REJECTED: {
const newPromise = new MPromise((resolve, reject) => rejectedFnCatch(resolve, reject, newPromise));
return newPromise;
}
case PENDING: {
const newPromise = new MPromise((resolve, reject) => {
this.FULFILLED_LIST.push(() => fulFilledFnCatch(resolve, reject, newPromise));
this.REJECTED_LIST.push(() => rejectedFnCatch(resolve, reject, newPromise));
});
return newPromise;
}
}
第七步.实现刚刚调用过的resolvePromise方法
resolvePromise(newPromise,x,resolve,reject) {
// 如果newPromise 和x同时指向同一对象,那么就要以返回一个以TypeError 的错误
if(newPromise === x) {
return reject(new TypeError('xxxxxxx'));
}
if(x instanceof MyPromise) {
// 如果x 为Promise ,则使 newPromise 接受x的状态
x.then((y) => {
this.resolvePromise(newPromise,y,resolve, reject);
});
} else if(typeof x === 'object'|| this.isFunction(x)) {
// 如果x 为对象或者函数
if(x === null) {
return resolve(x);
}
let then = null;
try{
// 把x.then 赋值给 then
then = x.then;
} catch(error) {
// 如果取x.then的值时候抛出错误e,以e为原因拒绝执行promsie
return reject(error);
}
//如果then是函数
if(this.isFunction(then)) {
let called = false;
// 将x作为函数的作用域 this调用
// 传递2个回调函数作为参数,第一个参数叫做resolvePromise ,第二个参数叫做rejectPromise
try{
this.call(x,
// 如果resolvePromise 以值为参数被调用,这运resolvePromise
(y) => {
// 如果resovlePromise 和rejectPromise
// 或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
//实现这条需要前面假一个变量called
if(called) {
return
}
called = true;
resolvePromise(newPromise, y, resovle, reject);
},
// 如果reslovPromise 以据因认为参数被调用,则以据因r拒绝执行promise
(r) => {
if(called) return;
called = true;
reject(r);
}
);
} catch(error) {
// 如果调用then方法抛出了异常e
// 如果 resolvePromise 或rejectPromise已经被调用,则忽略
if(called) return;
rejected(error);
}
} else {
// 如果then不是方法,这以x为参数执行promise
resolve(x);
}
} else {
// 如果x不为对象或者方法,以x为参数执行promise
resolve(x);
}
}
第八步.onFulfilled 和 onRejected是微任务,可以用queueMicrotask()方法包裹执行函数
const fulFilledFnCatch = (resolve, reject, newPromise) => {
queueMicrotask(() => {
try {
if (!this.isFunction(onFulfilled)) {
resolve(this.value);
} else {
const x = fulFilled_fn(this.value);
this.resolvePromise(newPromise, x, resolve, reject);
}
} catch (e) {
reject(e)
}
});
};
const rejectedFnCatch = (resolve, reject, newPromise) => {
queueMicrotask(() => {
try {
if (!this.isFunction(onRejected)) {
reject(this.reason);
} else {
const x = rejected_fn(this.reason);
this.resolvePromise(newPromise, x, resolve, reject);
}
} catch (e) {
reject(e);
}
});
}
第九步:catach方法
catch (onRejected) {
return this.then(null, onRejected);
}
第十步:promise.resovle
- 将现有对象转为Promise对象,如果 Promise.resolve 方法的参数,不是具有 then 方法的对象(又称 thenable 对象),则返回一个新的 Promise 对象,且它的状态为fulfilled。
static resolve(param) {
if (param instanceof MyPromise) {
return param;
}
return new MyPromise(function (resolve) {
resolve(param);
});
}
第十一步:promise.reject
- 返回一个新的Promise实例,该实例的状态为rejected。Promise.reject方法的参数reason,会被传递给实例的回调函数。
static reject(reason) {
return new MPromise((resolve, reject) => {
reject(reason);
});
}
第十二步:promise.race
- 该方法是将多个 Promise 实例,包装成一个新的 Promise 实例。 只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
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[i]).then(
(value) => {
return resolve(value);
},
(reason) => {
return reject(reason);
});
}
}
});
}