//实例化一个MyPromise对象
class MyPromise {
//创建constructor函数(考点:new实例化后之后发生了什么?答:1.创建一个空对象,作为要返回的对象实例。2.将这个空对象的原型__proto__,指向构造函数的prototype属性。3.将空对象赋值给函数内部的this关键字,即把constructor函数内部的this指向空对象。4.执行constructor内部代码。5.如果constructor内部有return并且是一个对象,那么new实例化返回的就是return后面的对象;否则不管return语句返回this对象,即前面创建的空对象。~这是因为new总是返回一个对象,如果对于普通函数而言,即使有return,但如果不是对象,则忽略,创建空对象,由于没有this指定属性,返回空对象。)new代码参考‘手写new.js'。
constructor(executor) {
//传入的参数是executor函数,即promise时指定的执行器函数。
//对于promise最重要的是状态(state)、成功的值(value)和失败的原因(reason)、执行器函数(executor)。
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
//由于then是同步挂载,故对于异步的promise要把指定的回调挂载到自身,需要时候再触发。
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
//定义resolve和reject状态改变函数。
const resolve = (value) => {
//promise A+规定其状态初始化为pending,并且之后只能改变一次,要么为Fuifilled;要么为Rejected;不允许之后再变化状态。
if (this.state === 'pending') {
//一旦执行函数,改变状态并且把传入的值赋值给自身的value属性;依次执行挂载到身上的所有方法。
this.state = 'Fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach(fn => fn());
} else {
return;
}
};
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'Rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn());
} else {
return;
}
};
//调用传入的执行器executor函数,将把resolve和reject两种状态改变函数作为参数传入。并且包裹一个错误捕获try/catch,一旦发生错误,比如传入一个未定义的变量,可以在这里捕获。
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
//定义then方法,并且把指定的成功和失败的回调作为参数传入。
then(onFulfilled, onRejected) {
//首先判断指定的回调类型,如果不是由一个函数,则把其包装成为一个函数。
if (typeof onFulfilled !== 'function') {
//对于指定的成功回调包装成普通箭头函数
onFulfilled = (value) => value
};
if (typeof onRejected !== 'function') {
//如果then指定的失败的回调不是一个函数,抛出错误;并且这个错误会在78或者101行捕获。
onRejected = (error) => { throw error }
}
//promise规定,每一个then返回一个新的promise对象。
const pp = new MyPromise((resolve, reject) => {
//x代表上一次promise指定的回调执行结果。这里包装一个定时器是为了模拟异步获取x值。
let x;
//Promise A+规定.then返回的promise对象pp是不允许等于回调函数的返回结果x。
//注意这里的this指向谁调用这个then方法,指向constructor中的this。
if (this.state === 'Fulfilled') {
//这里包装一个定时器是为了接收到.then返回的promise对象,必须要在初始化之后才能获得,因此利用定时器模拟异步,推向队列。
setTimeout(() => {
try {
//先执行回调并且把返回值赋值给x。
x = onFulfilled(this.value);
//调用resolvePromise函数,根据x的情况判断调用.then返回的promise是否成功或者失败。
this.resolvePromise(pp, x, resolve, reject);
} catch (error) {
reject(error)
}
}, 0)
};
if (this.state === 'Rejected') {
//捕获失败后抛出的错误
setTimeout(() => {
try {
x = onRejected(this.reason)
this.resolvePromise(pp, x, resolve, reject);
} catch (error) {
reject(error)
}
}, 0)
};
if (this.state === 'pending') {
//如果是异步的,先把指定的回调推向自身的回调数组保存。
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
x = onFulfilled(this.value);
this.resolvePromise(pp, x, resolve, reject);
} catch (error) {
reject(error)
}
}, 0)
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
x = onRejected(this.reason);
this.resolvePromise(pp, x, resolve, reject);
} catch (error) {
reject(error)
}
}, 0)
});
};
});
//返回一个promise实例。
return pp;
}
//定义一个处理回调返回的promise是否成功/失败的函数;注意这里传入参数resolve和reject是.then返回promise的resolve和reject。
resolvePromise(pp, x, resolve, reject) {
//这里不符合A+规范,返回一个错误。
if (pp === x) {
reject('TypeError')
}
//如果.then中指定的回调函数执行后的返回值如果是object或者function,默认是promise实例对象,对其自动绑定一个then方法,如果成功,则其传入的resolve执行,.then返回promise成功,反之失败。
if ((typeof x === 'object' && x !== null) || x === 'function') {
//非普通值
x.then(y => {
resolve(y)
}, r => {
reject(r);
});
} else {
//对于普通值,直接成功。
resolve(x)
}
}
//定义promise身上的静态成员~static(考点:静态成员与实例成员)
static all(arg) {
//同样规定返回的是一个promise对象。
return new MyPromise((resolve, reject) => {
//all执行的是并发操作
let valueAll = [], count = 0;
arg.forEach(item => {
item.then((value) => {
valueAll.push(value);
count++;
//全部成功才会把返回的实例状态变为成功
if (count === arg.length) {
resolve(valueAll)
};
}, (reason) => {
//只要失败,状态变为失败
reject(reason);
})
});
})
}
static race(arg) {
//类似all,这里是返回第一个promise对象返回的结果。
return new MyPromise((resolve, reject) => {
arg.forEach(item => {
item.then((value) => {
resolve(value)
}, (reason) => {
reject(reason);
})
});
})
}
static resolve() {
//返回一个成功的实例(undefined)
return new MyPromise((resolve, reject) => {
resolve();
})
}
static reject() {
//返回一个失败的实例(undefined)
return new MyPromise((resolve, reject) => {
reject();
})
}
};
部分代码片段和思路参考前端小夏老师https://b23.tv/3rmhkf3
仍有很多待优化的地方,欢迎各位大佬交流👏