手写Promise(2)

在这里插入图片描述

书接上回,本次推文将会继续讲解Promise的开发,以提高异步编程的能力。

一、回顾#

上次推文代码回顾:

class MyPromise{
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
constructor(executor){
this.status = MyPromise.PENDING;
this.value = null;
this.callbacks = [];
try{
executor(this.resolve.bind(this),this.reject.bind(this));
} catch{
this.reject(error);
}
}
resolve(value){
if(this.status == MyPromise.PENDING){
this.status = MyPromise.FULFILLED;
this.value = value;
this.callbacks.map(callback =>{
callback.onFulfilled(value);
});
}
}
reject(value){
if(this.status == MyPromise.PENDING){
this.status = MyPromise.REJECTED;
this.value = value;
this.callbacks.map(callback =>{
callback.onRejected(value);
});
}
}
then(onFulfilled,onRejected) {
if(typeof onFulfilled != "function"){
onFullfilled = value =>value;
}
if(typeof onRejected != "function"){
onRejected = value => value;
}
let promise = new MyPromise((resolve,reject) =>{
if(this.status == MyPromise.PENDING){
this.callbacks.push({
onFUlfilled: value =>{
this.parse(onFulfilled(this.value),resolve,reject);
},
onRejected: value =>{
this.parse(onRejected(this.value),resolve,reject);
}
});
}
if(this.status == MyPromise.FULFILLED){
setTimeout(()=>{
this.parse(onFulfilled(this.value),resolve,reject);
});
}
if(this.status == MyPromise.REJECTED){
setTime(()=>{
this.parse(onRejected(this.value),resolve,reject);
});
}
});
return promise;
}
parse(result,resolve,reject){
try{
if(result instanceof MyPromise){
result.then(resolve,reject);
}else{
resolve(result);
}
} catch(error){
reject(error);
}
}
}

接下来我们实现Promise的静态方法(方法添加到MyPromise类里面)

二、RESOLVE#

有时需要将现有对象转为 Promise 对象,Promise.resolve()方法就起到这个作用。

static resolve(value) {
return new MyPromise((resolve, reject) => {
if (value instanceof MyPromise) {
value.then(resolve, reject);
} else {
resolve(value);
}
});
}

使用普通值的测试:

MyPromise.resolve("前端收割机!!!!").then(value => {
console.log(value);
});
// 前端收割机!!!!

使用状态为fulfilledpromise值测试:

MyPromise.resolve(
new MyPromise(resolve => {
resolve("前端收割机!!!!");
})
).then(value => {
console.log(value);
});
// 前端收割机!!!!

使用状态为rejectedPromise测试

MyPromise.resolve(
new MyPromise((_, reject) => {
reject("前端收割机!!!!");
})
).then(
value => {
console.log(value);
},
reason => {
console.log(reason);
}
);
// 前端收割机!!!!

三、REJECT#

Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected

下面定义Promiserejecte方法

static reject(reason) {
return new MyPromise((_, reject) => {
reject(reason);
});
}

使用测试

MyPromise.reject("rejected").then(null, reason => {
console.log(reason);
});
// rejected

四、ALL#

Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

const p = Promise.all([p1, p2, p3]);

上面代码中,Promise.all()方法接受一个数组作为参数,p1p2p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。

p的状态由p1p2p3决定,分成两种情况。

(1)只有p1p2p3的状态都变成fulfilledp的状态才会变成fulfilled,此时p1p2p3的返回值组成一个数组,传递给p的回调函数。

(2)只要p1p2p3之中有一个被rejectedp的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

下面来实现Promise的all方法

static all(promises) {
let resolves = [];
return new MyPromise((resolve, reject) => {
promises.forEach((promise, index) => {
promise.then(
value => {
resolves.push(value);
if (resolves.length == promises.length) {
resolve(resolves);
}
},
reason => {
reject(reason);
}
);
});
});
}

来对所有Promise状态为fulfilled的测试:

let p1 = new MyPromise((resolve, reject) => {
resolve("前端收割机");
});
let p2 = new MyPromise((resolve, reject) => {
resolve("前端收割机");
});
let promises = MyPromise.all([p1, p2]).then(
promises => {
console.log(promises);
},
reason => {
console.log(reason);
}
);
// ["前端收割机","前端收割机"]

使用我们写的resolve进行测试:

let p1 = MyPromise.resolve("前端收割机1");
let p2 = MyPromise.resolve("前端收割机2");
let promises = HD.all([p1, p2]).then(
promises => {
console.log(promises);
},
reason => {
console.log(reason);
}
);
// ["前端收割机1","前端收割机2"]

其中一个Promise为rejected时的效果:

let p1 = MyPromise.resolve("前端收割机");
let p2 = MyPromise.reject("rejected");
let promises = MyPromise.all([p1, p2]).then(
promises => {
console.log(promises);
},
reason => {
console.log(reason);
}
);
// rejected

五、RACE#

Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

const p = Promise.race([p1, p2, p3]);

上面代码中,只要p1p2p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

Promise.race()方法的参数与Promise.all()方法一样,如果不是 Promise 实例,就会先调用下面讲到的Promise.resolve()方法,将参数转为 Promise 实例,再进一步处理。

下面实现Promise的race方法

static race(promises) {
return new MyPromise((resolve, reject) => {
promises.map(promise => {
promise.then(value => {
resolve(value);
});
});
});
}

我们来进行测试

let p1 = MyPromise.resolve("前端收割机1");
let p2 = MyPromise.resolve("前端收割机2");
let promises = MyPromise.race([p1, p2]).then(
promises => {
console.log(promises);
},
reason => {
console.log(reason);
}
);
// 前端收割机1

使用延迟Promise后的效果

let p1 = new MyPromise(resolve => {
setInterval(() => {
resolve("前端收割机1");
}, 2000);
});
let p2 = new MyPromise(resolve => {
setInterval(() => {
resolve("前端收割机2");
}, 1000);
});
let promises = MyPromise.race([p1, p2]).then(
promises => {
console.log(promises);
},
reason => {
console.log(reason);
}
);
// 前端收割机2

六、MyPromise整体代码#

下面就是这两次推文中手写Promise的整体代码,MyPromise的功能还不能完整模仿Promise的功能,真实的Promise中还具有Promise.try()Promise.any()Promise.allSettled()等静态方法,有兴趣的小伙伴可以自行尝试,这两节推文讲解Promise的开发,主要是提高异步编程的能力,以及对于Promise的理解。

class MyPromise{
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
constructor(executor){
this.status = MyPromise.PENDING;
this.value = null;
this.callbacks = [];
try{
executor(this.resolve.bind(this),this.reject.bind(this));
} catch{
this.reject(error);
}
}
resolve(value){
if(this.status == MyPromise.PENDING){
this.status = MyPromise.FULFILLED;
this.value = value;
this.callbacks.map(callback =>{
callback.onFulfilled(value);
});
}
}
reject(value){
if(this.status == MyPromise.PENDING){
this.status = MyPromise.REJECTED;
this.value = value;
this.callbacks.map(callback =>{
callback.onRejected(value);
});
}
}
then(onFulfilled,onRejected) {
if(typeof onFulfilled != "function"){
onFullfilled = value =>value;
}
if(typeof onRejected != "function"){
onRejected = value => value;
}
let promise = new MyPromise((resolve,reject) =>{
if(this.status == MyPromise.PENDING){
this.callbacks.push({
onFUlfilled: value =>{
this.parse(onFulfilled(this.value),resolve,reject);
},
onRejected: value =>{
this.parse(onRejected(this.value),resolve,reject);
}
});
}
if(this.status == MyPromise.FULFILLED){
setTimeout(()=>{
this.parse(onFulfilled(this.value),resolve,reject);
});
}
if(this.status == MyPromise.REJECTED){
setTime(()=>{
this.parse(onRejected(this.value),resolve,reject);
});
}
});
return promise;
}
parse(result,resolve,reject){
try{
if(result instanceof MyPromise){
result.then(resolve,reject);
}else{
resolve(result);
}
} catch(error){
reject(error);
}
}
static resolve(value) {
return new MyPromise((resolve, reject) => {
if (value instanceof MyPromise) {
value.then(resolve, reject);
} else {
resolve(value);
}
});
}
static reject(reason) {
return new MyPromise((_, reject) => {
reject(reason);
});
}
static all(promises) {
let resolves = [];
return new MyPromise((resolve, reject) => {
promises.forEach((promise, index) => {
promise.then(
value => {
resolves.push(value);
if (resolves.length == promises.length) {
resolve(resolves);
}
},
reason => {
reject(reason);
}
);
});
});
}
static race(promises) {
return new MyPromise((resolve, reject) => {
promises.map(promise => {
promise.then(value => {
resolve(value);
});
});
});
}
}