1.想要进行手写Promise,首先需要知道promise 的基本特性及用法
- 有一个Promise构造函数,传入resolve和reject两个参数,是两个可以执行的函数
- promise有三种状态:pending等待,fulfilled成功,rejected失败
- 状态pending 一旦转为fulfilled或者rejected,不能再更改
- resolve()方法为成功处理方法,将状态由pending转为fulfilled,且传入参数value
- reject()方法为失败处理方法,将状态由pending转为rejected,且传入参数reason
- then()方法接受两个参数,分别为onFulfilled和onRejected函数,当状态由pending转为fulfilled后执行onFulfilled函数,由pending转为rejected后指向onRejected函数
- .then()方法支持链式调用,创建Promise实例后,可以通过实例一直调用.then()方法触发
- 静态方法的实现:Promise.resolve(),Promise.reject(),Promise.all()
2.最终需要实现的效果:实现一个最基本的 promise案例
let p = new Promise((resolve, reject) => {
//支持异步操作
setTimeout(function(){
resolve('success')
},1000);
//resolve('success')
// reject('error')
})
p.then(data => {
console.log(data)
return data;
}).then(data=>{
console.log(data);
})
3.实现步骤
- 需要创建一个Promise类,并且添加一个回调方法 callback,作为Promise 的参数
- callback接收resolve 和 reject 作为参数,并且resolve 和 reject为两个函数且分别接受参数value和reason
- 定义promise的三种状态,实现then方法:定义promise的初始状态pending(后面两个状态在执行对应函数resolve和reject后进行更改);实现then方法:传入两个函数参数(onFulfilled和onRejected)通过判断状态执行对应函数
- then()方法可实现异步操作(用定时器进行测试)
- 实现链式调用
- 添加静态方法
3.1需要创建一个类,并且添加一个回调方法 callback,作为Promise 的参数
class MPromise {
constructor(callback) {
// 执行回调函数
callback();
}
}
3.2callback接收resolve 和 reject 作为参数,并且resolve 和 reject为两个函数且分别接受参数value和reason
class MPromise {
constructor(callback) {
// 定义成功返回参数。为什在构造器里面定义?
this.value = undefined;
// 定义失败返回参数
this.reason = undefined;
// 定义两个处理函数
const resolve = (value) => {
this.value = value;
console.log(this.value);
}
const reject = (reason) => {
this.reason = reason;
}
// 执行回调函数
callback(resolve,reject);
}
}
// MPromise类调用
let p = new MPromise((resolve,reject)=>{
resolve("success");
});
3.3定义和赋值promise的三种状态,实现then方法
定义promise的初始状态pending(后面两个状态在执行对应函数resolve和reject后进行更改)
实现then方法:传入
class MPromise {
constructor(callback) {
// 定义成功返回参数。为什在构造器里面定义?
this.value = undefined;
// 定义失败返回参数
this.reason = undefined;
// 定义promise的初始状态pending(后面两个状态在执行对应函数后进行更改)
this.state = 'pending';
// 定义两个处理函数
const resolve = (value) => {
this.value = value;
if(this.state === 'pending'){
this.state = 'fulfilled';
}
}
const reject = (reason) => {
this.reason = reason;
if(this.state === 'pending'){
this.state = 'rejected';
}
}
// 执行回调函数
callback(resolve,reject);
}
// then方法时MPromise创建的实例调用的所以在constructor外
// then()方法会接受两个函数参数(onFulfilled和onRejected)
then(onFulfilled,onRejected){
// 容错:onFulfilled,onRejected存在且为function时才能进行调用
let onFulfilledState = onFulfilled ? typeof onFulfilled === 'function' : true; //判断如果onFulfilled传入了则继续判断是否为function函数,否则直接返回true传入什么返回什么
let onRejectedState = onRejected ? typeof onRejected === 'function' : true;
if(onFulfilledState && onRejectedState){
// 根据对应状态调用不同的处理函数
if(this.state === 'fulfilled'){
onFulfilled(this.value);
}
if(this.state === 'rejected'){
onRejected(this.value);
}
}
}
}
// MPromise类调用
let p = new MPromise((resolve,reject)=>{
resolve("success");
});
p.then((data)=>{
console.log(data);
});
3.4 then()方法可实现异步操作
以上代码,如果加入定时器实现异步就会发现打印不了
// MPromise类调用
let p = new MPromise((resolve,reject)=>{
setTimeout(function (){
resolve("success");
},1000)
});
p.then((data)=>{
console.log(data);
});
给then方法加入返回值 new MPromise发现还是没有返回
then(onFulfilled, onRejected) {
return new MPromise((resolve, reject) => {
// 容错:onFulfilled,onRejected存在且为function时才能进行调用
let onFulfilledState = onFulfilled ? typeof onFulfilled === 'function' : true; //判断如果onFulfilled传入了则继续判断是否为function函数,否则直接返回true传入什么返回什么
let onRejectedState = onRejected ? typeof onRejected === 'function' : true;
if (onFulfilledState && onRejectedState) {
// 根据对应状态调用不同的处理函数
if (this.state === 'fulfilled') {
resolve(onFulfilled(this.value));
}
if (this.state === 'rejected') {
reject(onRejected(this.value));
}
}
});
}
为什么加入了new MPromise()后还是没有返回?因为这里是通过setTimeout()进行异步操作,当执行then方法时,回调函数中的resolve()并未执行完成,就会导致状态一直是pending
分析:发现p.then方法里面的函数不会触发,setTimeout()里面的resolve也没有执行
为什么加入了new MPromise()后还是没有返回?因为new MPromise()时,发现setTimeout()定时任务就会将其放到异步队列里面,而通过p.then()调用方法时,回调函数中的resolve()并未执行完成,this.state状态一直处于pending状态,自然也就没有调用resolve(onFulfilled())方法
解决思路:(观察者模式)
既然 then 自己无法知道 resolve 什么时候执行,是否执行了,那resolve执行完后就需要有个东西告诉then,执行完了。
即在then里面判断为pending状态时,将成功和失败的方法分别记录到一个数组里面,然后再分别再resolve()和reject()触发时,再去遍历执行数组存进去的函数
关键代码:
// 设置数组用于存放异步队列中所有的resolve和reject函数
this.onResolveCallback = [];
this.onRejectCallback = [];
// 定义两个处理函数
const resolve = (value) => {
this.value = value;
if (this.state === 'pending') {
this.state = 'fulfilled';
}
if (this.state === 'fulfilled') {
this.onResolveCallback.forEach(resolveCb => resolveCb(this.value));
}
}
const reject = (reason) => {
this.reason = reason;
if (this.state === 'pending') {
this.state = 'rejected';
}
if (this.state === 'rejected') {
this.onRejectCallback.forEach(rejectCb => rejectCb(this.reason));
}
}
.......
// 当异步执行时,状态会一直为pending
if(this.state === 'pending') {
this.onResolveCallback.push(() => {
onFulfilled(this.value)
})
this.onRejectCallback.push(() => {
onRejected(this.reason)
})
}
完整代码:
class MPromise {
constructor(callback) {
// 定义成功返回参数。为什在构造器里面定义?
this.value = undefined;
// 定义失败返回参数
this.reason = undefined;
// 定义promise的初始状态pending(后面两个状态在执行对应函数后进行更改)
this.state = 'pending';
// 设置数组用于存放异步队列中所有的resolve和reject函数
this.onResolveCallback = [];
this.onRejectCallback = [];
// 定义两个处理函数
const resolve = (value) => {
this.value = value;
if (this.state === 'pending') {
this.state = 'fulfilled';
}
if (this.state === 'fulfilled') {
this.onResolveCallback.forEach(resolveCb => resolveCb(this.value));
}
}
const reject = (reason) => {
this.reason = reason;
if (this.state === 'pending') {
this.state = 'rejected';
}
if (this.state === 'rejected') {
this.onRejectCallback.forEach(rejectCb => rejectCb(this.reason));
}
}
// 执行回调函数
callback(resolve, reject);
}
// then方法时MPromise创建的实例调用的所以在constructor外
// then()方法会接受两个函数参数(onFulfilled和onRejected)
then(onFulfilled, onRejected) {
return new MPromise((resolve, reject) => {
// 容错:onFulfilled,onRejected存在且为function时才能进行调用
let onFulfilledState = onFulfilled ? typeof onFulfilled === 'function' : true; //判断如果onFulfilled传入了则继续判断是否为function函数,否则直接返回true传入什么返回什么
let onRejectedState = onRejected ? typeof onRejected === 'function' : true;
if (onFulfilledState && onRejectedState) {
// 根据对应状态调用不同的处理函数
if (this.state === 'fulfilled') {
resolve(onFulfilled(this.value));
}
if (this.state === 'rejected') {
reject(onRejected(this.value));
}
// 当异步执行时,状态会一直为pending
if (this.state === 'pending') {
// push进去的是下一次resolve函数
this.onResolveCallback.push(()=>onFulfilled(this.value));
this.onRejectCallback.push(()=>onRejected(this.reason));
}
}
});
}
}
// MPromise类调用
let p = new MPromise((resolve, reject) => {
setTimeout(function () {
resolve("success");
// reject("error");
}, 1000)
});
p.then((data) => {
console.log(data);
return data
},err=>{
console.log(err);
}).then((data)=>{
console.log("第二次调用then",data);
})
3.5实现链式调用
链式调用的本质是需要调用then方法后返回一个promise对象,且内部仍然会执行resolve和reject函数
特点:后面每个.then()方法中能获得上一个.then()返回的参数
解决:push进数组时再通过resolve方法执行就能重新通过then进行调用
// 当异步执行时,状态会一直为pending
if (this.state === 'pending') {
this.onResolveCallback.push(()=>resolve(onFulfilled(this.value)));
this.onRejectCallback.push(()=>resolve(onRejected(this.reason)));
}
3.6添加静态方法(Promise.resolve,Promise.reject,Promise.all)
其实就是单独调用new MPromise里面的resolve方法
// 其实就是单独调用new MPromise里面的resolve方法
static resolve = (value) => new MPromise((resolve,reject)=>resolve(value));
static reject = (reason) => new MPromise((resolve,reject)=>resolve(reason));
MPromise.resolve("这是静态方法MPromise.resolve调用").then((data)=>{
console.log(data);
return data;
}).then(data=>{
console.log("第二次调用静态方法MPromise.resolve调用",data);
})
MPromise.reject("这是静态方法MPromise.reject调用").then((error)=>{
console.log(error);
})
MPromise.all() 关键是需要在循环中调用promise.then()方法向下执行,最后判断数组中所有promise执行完后,通过resolve返回结果
static all = (promiseArr) => new MPromise((resolve, reject)=>{
// 使用数组存放所有MPromise传入的参数数据
let results = [];
// 使用count记录处理的MPromise,每处理一个+1,直到最后一个处理完就返回参数数组
let count = 0;
promiseArr.forEach((promise,index)=>{
promise.then(item=>{
results[index] = item;
count++;
console.log(promise.value);
// 注意此处用数组下标判断会出现问题:setTimeout()异步的会等results其他输出后第二次输出
if(count === promiseArr.length){
resolve(results);
}
});
});
})
let p1 = new MPromise(1);
let p2 = new MPromise((resolve, reject) => {
setTimeout(function(){
resolve("p2");
}, 2000);
})
let p3 = new MPromise((resolve, reject) => {
resolve("p3");
})
let p4 = new MPromise((resolve, reject) => {
resolve("p4");
})
MPromise.all([p1, p2, p3, p4]).then(result => {
console.log(result);
});
4.问题(实现Promise.all()时为什么不能通过数组循环的index判断if( index+1 === promiseArr.length )所有的promise已执行完成可以返回结果了)
手写promise中,Promise.all方法实现时,为什么不能使用index进行判断(异步时不会同时打印,等其他打印完再打印异步的)
使用index判断打印的结果为:p1,p3,p4。p2过一秒后才打印
static all = (promiseArr) => new MPromise((resolve, reject)=>{
// 使用数组存放所有MPromise传入的参数数据
let results = [];
// 使用count记录处理的MPromise,每处理一个+1,直到最后一个处理完就返回参数数组
let count = 0;
promiseArr.forEach((promise,index)=>{
promise.then(item=>{
results[index] = item;
count++;
console.log(promise.value);
// 注意此处用数组下标判断会出现问题:setTimeout()异步的会等results其他输出后第二次输出
if(count === promiseArr.length){
resolve(results);
}
});
});
})
问题分析:
promise.then()被调用才能表示当前promise执行完,而index是在外层的,所以用index判断会输出有问题
5.完整代码
/*
实现功能:
有一个Promise构造函数,传入resolve和reject两个参数,是两个可以执行的函数
promise有三种状态:pending等待,fulfilled成功,rejected失败
状态pending 一旦转为fulfilled或者rejected,不能再更改
resolve()方法为成功处理方法,将状态由pending转为fulfilled,且传入参数value
reject()方法为失败处理方法,将状态由pending转为rejected,且传入参数reason
then()方法接受两个参数,分别为onFulfilled和onRejected函数,当状态由pending转为fulfilled后执行onFulfilled函数,由pending转为rejected后指向onRejected函数
.then()方法支持链式调用,创建Promise实例后,可以通过实例一直调用.then()方法触发
静态方法的实现:Promise.resolve(),Promise.reject(),Promise.all()
基本步骤:
需要创建一个Promise类,并且添加一个回调方法 callback,作为Promise 的参数
callback接收resolve 和 reject 作为参数
定义promise的三种状态,实现then方法
then()方法可实现异步操作(用定时器进行测试)
实现链式调用
添加静态方法
*/
// 问题:写在constructor里面的函数和写在constructor外的函数区别
// constructor里面的函数,通过构造方法创建时就必须传入回调函数
class MPromise {
constructor(callback) {
// 定义成功返回参数。为什在构造器里面定义?
this.value = undefined;
// 定义失败返回参数
this.reason = undefined;
// 定义promise的初始状态pending(后面两个状态在执行对应函数后进行更改)
this.state = 'pending';
// 设置数组用于存放异步队列中所有的resolve和reject函数
this.onResolveCallback = [];
this.onRejectCallback = [];
// 定义两个处理函数
const resolve = (value) => {
this.value = value;
if (this.state === 'pending') {
this.state = 'fulfilled';
}
if (this.state === 'fulfilled') {
this.onResolveCallback.forEach(resolveCb => resolveCb(this.value));
}
}
const reject = (reason) => {
this.reason = reason;
if (this.state === 'pending') {
this.state = 'rejected';
}
if (this.state === 'rejected') {
this.onRejectCallback.forEach(rejectCb => rejectCb(this.reason));
}
}
// 执行回调函数(对传入非function的进行处理)
typeof callback === 'function'? callback(resolve, reject): resolve(callback);
}
// then方法时MPromise创建的实例调用的所以在constructor外
// then()方法会接受两个函数参数(onFulfilled和onRejected)
then(onFulfilled, onRejected) {
return new MPromise((resolve, reject) => {
// 容错:onFulfilled,onRejected存在且为function时才能进行调用
let onFulfilledState = onFulfilled ? typeof onFulfilled === 'function' : true; //判断如果onFulfilled传入了则继续判断是否为function函数,否则直接返回true传入什么返回什么
let onRejectedState = onRejected ? typeof onRejected === 'function' : true;
if (onFulfilledState && onRejectedState) {
// 根据对应状态调用不同的处理函数
if (this.state === 'fulfilled') {
resolve(onFulfilled(this.value));
}
if (this.state === 'rejected') {
reject(onRejected(this.value));
}
// 当异步执行时,状态会一直为pending
if (this.state === 'pending') {
// push进去的是下一次resolve函数
this.onResolveCallback.push(() => resolve(onFulfilled(this.value)));
this.onRejectCallback.push(() => resolve(onRejected(this.reason)));
}
}
});
}
// 其实就是单独调用new MPromise里面的resolve方法
static resolve = (value) => new MPromise((resolve, reject) => resolve(value));
static reject = (reason) => new MPromise((resolve, reject) => resolve(reason));
// 关键是需要在循环中调用promise.then()方法向下执行,最后判断数组中所有promise执行完后,通过resolve返回结果
static all = (promiseArr) => new MPromise((resolve, reject)=>{
// 使用数组存放所有MPromise传入的参数数据
let results = [];
// 使用count记录处理的MPromise,每处理一个+1,直到最后一个处理完就返回参数数组
let count = 0;
promiseArr.forEach((promise,index)=>{
promise.then(item=>{
results[index] = item;
count++;
console.log(promise.value);
// 注意此处用数组下标判断会出现问题:setTimeout()异步的会等results其他输出后第二次输出
if(count === promiseArr.length){
resolve(results);
}
});
});
})
}
// // MPromise类调用
// let p = new MPromise((resolve, reject) => {
// setTimeout(function () {
// resolve("success");
// // reject("error");
// }, 1000)
// });
// p.then((data) => {
// console.log(data);
// return data
// },err=>{
// console.log(err);
// }).then((data)=>{
// console.log("第二次调用then",data);
// })
// MPromise.resolve("这是静态方法MPromise.resolve调用").then((data)=>{
// console.log(data);
// return data;
// }).then(data=>{
// console.log("第二次调用静态方法MPromise.resolve调用",data);
// })
// MPromise.reject("这是静态方法MPromise.reject调用").then((error)=>{
// console.log(error);
// })
let p1 = new MPromise(1);
let p2 = new MPromise((resolve, reject) => {
setTimeout(function(){
resolve("p2");
}, 2000);
})
let p3 = new MPromise((resolve, reject) => {
resolve("p3");
})
let p4 = new MPromise((resolve, reject) => {
resolve("p4");
})
MPromise.all([p1, p2, p3, p4]).then(result => {
console.log(result);
});
// // Promise类调用
// let p = new Promise((resolve, reject) => {
// // 执行resolve或者reject函数,并传入参数
// setTimeout(function (){
// resolve("success");
// },1000)
// });
// p.then((data) => {
// console.log(data);
// })