书接上回,本次推文将会继续讲解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);
});
// 前端收割机!!!!
使用状态为fulfilled
的promise
值测试:
MyPromise.resolve(
new MyPromise(resolve => {
resolve("前端收割机!!!!");
})
).then(value => {
console.log(value);
});
// 前端收割机!!!!
使用状态为rejected
的Promise
测试
MyPromise.resolve(
new MyPromise((_, reject) => {
reject("前端收割机!!!!");
})
).then(
value => {
console.log(value);
},
reason => {
console.log(reason);
}
);
// 前端收割机!!!!
三、REJECT
Promise.reject(reason)
方法也会返回一个新的 Promise 实例,该实例的状态为rejected
。
下面定义Promise
的rejecte
方法
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()
方法接受一个数组作为参数,p1
、p2
、p3
都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve
方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()
方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。
p
的状态由p1
、p2
、p3
决定,分成两种情况。
(1)只有p1
、p2
、p3
的状态都变成fulfilled
,p
的状态才会变成fulfilled
,此时p1
、p2
、p3
的返回值组成一个数组,传递给p
的回调函数。
(2)只要p1
、p2
、p3
之中有一个被rejected
,p
的状态就变成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]);
上面代码中,只要p1
、p2
、p3
之中有一个实例率先改变状态,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);
});
});
});
}
}