实现Promise
1.最近写代码的时候使用到很多promise,于是好奇promise 内部是怎么实现的,是怎么运转的。所以决定自己参考源码理解来实现一下。
- 从使用方法 new Promise(function(resolve,reject){…}); 可以知道Promise 构造函数接收一个函数作为参数,并且构造函数内部会有resolve,与reject 方法 作为参数。
class MyPromise {
constructor(fn){
if(typeof fn !== 'function'){
throw new Error('Promise resolver undefined is not a function');
}
fn(this.resolve.bind(this),this.reject.bind(this));
}
resolve(status){
}
reject(status){
}
}
- 从promise的特性可以知道 promise 有3个状态 执行成功 => fulfilled,执行失败 => rejected, 执行中 => pending. 所以我们还需要定义一个 promise状态属性。同时需要一个promise的value值。
- 我们new 一个 promise 发现 它的状态值的默认值为 pending ,它的值默认为 undefined 所以将上述代码完善。
class MyPromise {
constructor(fn){
if(typeof fn !== 'function'){
throw new Error('Promise resolver undefined is not a function');
}
this.promiseStatus = 'pending'; //初始化promise 的状态
this.promiseValue = 'undefined'; //初始化promise 的值
fn(this.resolve.bind(this),this.reject.bind(this));
}
resolve(value){
}
reject(value){
}
}
- 接下来我们来完善 promise 的 resolve 方法,从使用上我们知道 resolve 方法接收一个任意类型的值,并且会将它赋值给 promise的value,同时执行完 resolve 之后会将promise 的状态值修改为 fulfilled。reject 方法同理
class MyPromise {
constructor(fn){
if(typeof fn !== 'function'){
throw new Error('Promise resolver undefined is not a function');
}
this.promiseStatus = 'pending'; //初始化promise 的状态
this.promiseValue = 'undefined'; //初始化promise 的值
fn(this.resolve.bind(this),this.reject.bind(this));//此处用 bind 方法 绑定方法的 this 指向 为 当前promise对象
}
resolve(value){
if(this.promiseStatus !== 'pending') return; // promise的状态值 只能 由pending => fulfiled 或 pending => rejected,并且状态一旦更改,就不能再更改了。 所以此处将 非pending 状态的情况排除
this.promiseStatus = 'fulfiled'; //将状态 修改为 执行成功
this.promiseValue = value;
}
// 同理 实现 reject
reject(value){
if(this.promiseStatus !== 'pending') return;
this.promiseStatus = 'rejected';
this.promiseValue = value;
}
}
- 上述状态更改处理 少考虑了 当传入的 是 promise 对象的情况
- 我们使用 Promise 来测试一下
- 发现 当resolve 方法 传入的参数为 promise 对象时,此时Promise 的状态和值 会依赖与 传入的Promise对象的状态和值。
- 而 reject 方法 传入的参数为Promise 对象时,状态不会受传入的Promise对象的状态影响,值直接等于传入的Promise对象,而不是 传入的Promise的值。
- 但是二者都会让 传入的Promise执行完成之后,再进行后续的操作。
- 根据上述的结果 对Promise resolve 和 reject 进行改进, 由于 reject方法 改变状态不受 传入 Promise对象的状态影响,所以reject是不需要更改。
class MyPromise {
constructor(fn){
if(typeof fn !== 'function'){
throw new Error('Promise resolver undefined is not a function');
}
this.promiseStatus = 'pending'; //初始化promise 的状态
this.promiseValue = 'undefined'; //初始化promise 的值
fn(this.resolve.bind(this),this.reject.bind(this));//此处用 bind 方法 绑定方法的 this 指向 为 当前promise对象
}
resolve(value){
if(this.promiseStatus !== 'pending') return; // promise的状态值 只能 由pending => fulfiled 或 pending => rejected,并且状态一旦更改,就不能再更改了。 所以此处将 非pending 状态的情况排除
this.promiseStatus = 'fulfiled'; //将状态 修改为 执行成功
if(value instanceof MyPromise){ //判断MyPromise 是否在value的原型链上, 存在说明 是MyPromise 构造出来的对象
/*
此处 需要做的操作就是 将传入的Promise 对象 执行完成之后再改变值,此时我们要使用到Promise的then方法确保传入的Promise 执行完成。我们下面就来实现 then方法
*/
}else{ //非Promise 对象 直接修改
this.promiseValue = value;
}
}
// 同理 实现 reject
reject(value){
if(this.promiseStatus !== 'pending') return;
this.promiseStatus = 'rejected';
this.promiseValue = value;
}
}
- 下面来实现 then方法,首先需要知道的是then 方法会添加成功回调,以及失败回调。当resolve执行时,就会依次执行所有 then 方法添加(注册)的成功回调函数,当reject执行时,就会一次执行所有 then 方法 添加的失败回调函数。
- 由上述执行结果 可以得出 then 方法会返回一个 新的 Promise 对象,而不是在之前的Promise对象上进行值的更改,而这个新的 Promise对象 的值 就是 传入 then 方法 内的 回调的 返回值。
- 下面进行 then方法的实现
class MyPromise {
constructor(fn){
if(typeof fn !== 'function'){
throw new Error('Promise resolver undefined is not a function');
}
this.promiseStatus = 'pending'; //初始化promise 的状态
this.promiseValue = 'undefined'; //初始化promise 的值
this.fulfilledQueue = []; // 用于存储 then 方法注册的 成功回调
this.rejectedQueue = [];// 用于存储 then 方法 注册的 失败回调
fn(this.resolve.bind(this),this.reject.bind(this));//此处用 bind 方法 绑定方法的 this 指向 为 当前promise对象
}
resolve(value){
if(this.promiseStatus !== 'pending') return; // promise的状态值 只能 由pending => fulfiled 或 pending => rejected,并且状态一旦更改,就不能再更改了。 所以此处将 非pending 状态的情况排除
this.promiseStatus = 'fulfiled'; //将状态 修改为 执行成功
if(value instanceof MyPromise){ //判断MyPromise 是否在value的原型链上, 存在说明 是MyPromise 构造出来的对象
/*
此处 需要做的操作就是 将传入的Promise 对象 执行完成之后再改变值,此时我们要使用到Promise的then方法确保传入的Promise 执行完成。我们下面就来实现 then方法
*/
}else{ //非Promise 对象 直接修改
this.promiseValue = value;
}
}
// 同理 实现 reject
reject(value){
if(this.promiseStatus !== 'pending') return;
this.promiseStatus = 'rejected';
this.promiseValue = value;
}
then(successCallBack,failCallBack){
return new MyPromise((newResolve,newReject)=>{ // 此处使用箭头函数 可以确保 this 该方法内 this 指向 调用 then 方法的 promise 对象
// 封装一个 执行成功的(resolve方法触发) 回调函数
const onFulfilled = value =>{
if(typeof successCallBack !== 'function'){
newResolve(value); //如果 then方法传入的参数不是函数 那么直接按上一个Promise 的值作为then方法返回新的Promise的值
}else{
//是函数 就直接执行,并且将执行结果(函数返回值) 作为 新的promise的value抛出
let result = succCallBack(value);
if(result instanceof MyPromise){ //如果返回值是一个promise 对象则需要等该promise执行完成(状态值不为pending),将执行完的结果作为 新的promise的value值
result.then(val=>{
newResolve(val);
},err=>{
newReject(err);
})
}else{
newResolve(result);
}
}
}
//封装一个 执行失败的 (reject方法触发) 回调函数
const onRejected = error =>{
if(typeof failCallBack !== 'function'){
newReject(error);
}else{
const result = failCallBack(error);
if(result instanceof MyPromise){
result.then(val=>{
newReject(val);
},err=>{
newReject(err);
})
}else{
newReject(error);
}
}
}
switch(this.promiseStatus){ // 根据promise 状态值来判断 执行相应的操作
case 'pending': //当状态为pending 时 将 上述函数 加入对应的 队列 等待被执行
this.fulfilledQueue.push(onFulfilled);
this.rejectedQueue.push(onRejected);
break;
case 'fulfilled':
onFulfilled(this.promiseValue);
break;
case 'rejected':
onRejected(this.promiseValue);
break;
}
})
}
}
- then 方法实现了,再将 resolve 方法完善
class MyPromise {
constructor(fn){
if(typeof fn !== 'function'){
throw new Error('Promise resolver undefined is not a function');
}
this.promiseStatus = 'pending'; //初始化promise 的状态
this.promiseValue = 'undefined'; //初始化promise 的值
this.fulfilledQueue = []; // 用于存储 then 方法注册的 成功回调
this.rejectedQueue = [];// 用于存储 then 方法 注册的 失败回调
fn(this.resolve.bind(this),this.reject.bind(this));//此处用 bind 方法 绑定方法的 this 指向 为 当前promise对象
}
resolve(value){
const run = (()=>{
let thenCallBack='';
const runFulfilled = (value)=>{ //接收 resolve传入的 value值
while(thenCallBack = this.fulfilledQueue.shift()){ //每次都取出队列第一个then 回调 进行执行 直到所有then 方法的成功回调方法执行完成
typeof thenCallBack === 'function' && thenCallBack(value);
}
}
const runRejected = (error) =>{
while(thenCallBack = this.rejectedQueue.shift()){
typeof thenCallBack === 'function' && thenCallBack(error);
}
}
// 利用闭包 私有化 上述 属性 和方法
return ()=>{
if(this.promiseStatus !== 'pending') return; // promise的状态值 只能 由pending => fulfiled 或 pending => rejected,并且状态一旦更改,就不能再更改了。 所以此处将 非pending 状态的情况排除
this.promiseStatus = 'fulfiled'; //将状态 修改为 执行成功
if(value instanceof MyPromise){ //判断MyPromise 是否在value的原型链上, 存在说明 是MyPromise 构造出来的对象
/*
此处 需要做的操作就是 将传入的Promise 对象 执行完成之后再改变值,此时我们要使用到Promise的then方法确保传入的Promise 执行完成。我们下面就来实现 then方法
*/
value.then(res=>{
this.promiseValue = res;
runFulfilled(res);
},err=>{
this.promiseValue = err;
this.promiseStatus = 'rejected';// 失败 时 同时要将 Promise 状态进行更改
runRejected(err);
})
}else{ //非Promise 对象 直接修改
this.promiseValue = value;
}
}
}).call(this);
}
// 同理 实现 reject
reject(value){
if(this.promiseStatus !== 'pending') return;
this.promiseStatus = 'rejected';
this.promiseValue = value;
}
then(successCallBack,failCallBack){
return new MyPromise((newResolve,newReject)=>{ // 此处使用箭头函数 可以确保 this 该方法内 this 指向 调用 then 方法的 promise 对象
// 封装一个 执行成功的(resolve方法触发) 回调函数
const onFulfilled = value =>{
if(typeof successCallBack !== 'function'){
newResolve(value); //如果 then方法传入的参数不是函数 那么直接按上一个Promise 的值作为then方法返回新的Promise的值
}else{
//是函数 就直接执行,并且将执行结果(函数返回值) 作为 新的promise的value抛出
let result = succCallBack(value);
if(result instanceof MyPromise){ //如果返回值是一个promise 对象则需要等该promise执行完成(状态值不为pending),将执行完的结果作为 新的promise的value值
result.then(val=>{
newResolve(val);
},err=>{
newReject(err);
})
}else{
newResolve(result);
}
}
}
//封装一个 执行失败的 (reject方法触发) 回调函数
const onRejected = error =>{
if(typeof failCallBack !== 'function'){
newReject(error);
}else{
const result = failCallBack(error);
if(result instanceof MyPromise){
result.then(val=>{
newReject(val);
},err=>{
newReject(err);
})
}else{
newReject(error);
}
}
}
switch(this.promiseStatus){ // 根据promise 状态值来判断 执行相应的操作
case 'pending': //当状态为pending 时 将 上述函数 加入对应的 队列 等待被执行
this.fulfilledQueue.push(onFulfilled);
this.rejectedQueue.push(onRejected);
break;
case 'fulfilled':
onFulfilled(this.promiseValue);
break;
case 'rejected':
onRejected(this.promiseValue);
break;
}
})
}
}
- 上述代码已经完成了promise 基本的使用方法,但是还有一个问题,上述实现中resolve 与 reject 方法是同步方法,而真正的Promise 的resolve 和 reject 方法 是异步的,所以再将上述 resolve 与 reject 方法进行改进。
class MyPromise {
constructor(fn){
if(typeof fn !== 'function'){
throw new Error('Promise resolver undefined is not a function');
}
this.promiseStatus = 'pending'; //初始化promise 的状态
this.promiseValue = 'undefined'; //初始化promise 的值
this.fulfilledQueue = []; // 用于存储 then 方法注册的 成功回调
this.rejectedQueue = [];// 用于存储 then 方法 注册的 失败回调
fn(this.resolve.bind(this),this.reject.bind(this));//此处用 bind 方法 绑定方法的 this 指向 为 当前promise对象
}
resolve(value){
const run = (()=>{
let thenCallBack='';
const runFulfilled = (value)=>{ //接收 resolve传入的 value值
while(thenCallBack = this.fulfilledQueue.shift()){ //每次都取出队列第一个then 回调 进行执行 直到所有then 方法的成功回调方法执行完成
typeof thenCallBack === 'function' && thenCallBack(value);
}
}
const runRejected = (error) =>{
while(thenCallBack = this.rejectedQueue.shift()){
typeof thenCallBack === 'function' && thenCallBack(error);
}
}
// 利用闭包 私有化 上述 属性 和方法
return ()=>{
if(this.promiseStatus !== 'pending') return; // promise的状态值 只能 由pending => fulfiled 或 pending => rejected,并且状态一旦更改,就不能再更改了。 所以此处将 非pending 状态的情况排除
this.promiseStatus = 'fulfiled'; //将状态 修改为 执行成功
if(value instanceof MyPromise){ //判断MyPromise 是否在value的原型链上, 存在说明 是MyPromise 构造出来的对象
/*
此处 需要做的操作就是 将传入的Promise 对象 执行完成之后再改变值,此时我们要使用到Promise的then方法确保传入的Promise 执行完成。我们下面就来实现 then方法
*/
value.then(res=>{
this.promiseValue = res;
runFulfilled(res);
},err=>{
this.promiseValue = err;
this.promiseStatus = 'rejected';// 失败 时 同时要将 Promise 状态进行更改
runRejected(err);
})
}else{ //非Promise 对象 直接修改
this.promiseValue = value;
}
}
}).call(this);
setTimeout(run);
}
// 同理 实现 reject
reject(value){
if(this.promiseStatus !== 'pending') return;
this.promiseStatus = 'rejected';
const run = (()=>{
let thenCallBack = '';
const runFulfilled = (value)=>{ //接收 resolve传入的 value值
while(thenCallBack = this.fulfilledQueue.shift()){ //每次都取出队列第一个then 回调 进行执行 直到所有then 方法的成功回调方法执行完成
typeof thenCallBack === 'function' && thenCallBack(value);
}
}
const runRejected = (error) =>{
while(thenCallBack = this.rejectedQueue.shift()){
typeof thenCallBack === 'function' && thenCallBack(error);
}
}
return ()=>{
if(this.promiseStatus !== 'pending') return; // promise的状态值 只能 由pending => fulfiled 或 pending => rejected,并且状态一旦更改,就不能再更改了。 所以此处将 非pending 状态的情况排除
this.promiseStatus = 'rejected'; //将状态 修改为 执行成功
if(value instanceof MyPromise){
this.promiseValue = value.then(res=>{//reject 方法 不依赖 传入的Promise 状态值所以此处即便传入的Prmise对象状态为 成功 也不修改当前Promise 状态,并且以传入的Promise对象作为当前Promise的值runRejected(res);
return res;
},err=>{
runRejected(err);
return err;
});
}else{
this.promiseValue = value;
runRejected(value);
}
}
}).call(this);
setTimeout(run);
}
then(successCallBack,failCallBack){
return new MyPromise((newResolve,newReject)=>{ // 此处使用箭头函数 可以确保 this 该方法内 this 指向 调用 then 方法的 promise 对象
// 封装一个 执行成功的(resolve方法触发) 回调函数
const onFulfilled = value =>{
if(typeof successCallBack !== 'function'){
newResolve(value); //如果 then方法传入的参数不是函数 那么直接按上一个Promise 的值作为then方法返回新的Promise的值
}else{
//是函数 就直接执行,并且将执行结果(函数返回值) 作为 新的promise的value抛出
let result = succCallBack(value);
if(result instanceof MyPromise){ //如果返回值是一个promise 对象则需要等该promise执行完成(状态值不为pending),将执行完的结果作为 新的promise的value值
result.then(val=>{
newResolve(val);
},err=>{
newReject(err);
})
}else{
newResolve(result);
}
}
}
//封装一个 执行失败的 (reject方法触发) 回调函数
const onRejected = error =>{
if(typeof failCallBack !== 'function'){
newReject(error);
}else{
const result = failCallBack(error);
if(result instanceof MyPromise){
result.then(val=>{
newReject(val);
},err=>{
newReject(err);
})
}else{
newReject(error);
}
}
}
switch(this.promiseStatus){ // 根据promise 状态值来判断 执行相应的操作
case 'pending': //当状态为pending 时 将 上述函数 加入对应的 队列 等待被执行
this.fulfilledQueue.push(onFulfilled);
this.rejectedQueue.push(onRejected);
break;
case 'fulfilled':
onFulfilled(this.promiseValue);
break;
case 'rejected':
onRejected(this.promiseValue);
break;
}
})
}
}
- 上述 使用 setTimeout 来实现 异步调用,实现异步执行的问题。
但是会出现执行顺序异常的问题 如下述代码
正常执行顺序应该为
应该先执行 promise 的回调,再执行定时器 (原因是因为 promise 注册的任务为 微任务 而 setTimeout 为宏任务,具体参考js 的事件循环机制) - 根据上述问题,我们继续改进。
- 这里不能再使用到 setTimeout 这类的宏任务来实现promise ,应该使用到微任务来实现。
- 所有微任务 大概只有 promise / process.nextTrick/MutationObserver , 既然我们是实现 promise 当然不能使用到正常的promise , 而 process.nextTrick 方法只有在node 环境中才存在,所以最终我们只能使用MutationObserver 方法来实现。 实现代码如下
class MyPromise {
constructor(fn){
if(typeof fn !== 'function'){
throw new Error('Promise resolver undefined is not a function');
}
this.promiseStatus = 'pending'; //初始化promise 的状态
this.promiseValue = 'undefined'; //初始化promise 的值
this.fulfilledQueue = []; // 用于存储 then 方法注册的 成功回调
this.rejectedQueue = [];// 用于存储 then 方法 注册的 失败回调
fn(this.resolve.bind(this),this.reject.bind(this));//此处用 bind 方法 绑定方法的 this 指向 为 当前promise对象
}
resolve(value){
const run = (()=>{
let thenCallBack='';
const runFulfilled = (value)=>{ //接收 resolve传入的 value值
while(thenCallBack = this.fulfilledQueue.shift()){ //每次都取出队列第一个then 回调 进行执行 直到所有then 方法的成功回调方法执行完成
typeof thenCallBack === 'function' && thenCallBack(value);
}
}
const runRejected = (error) =>{
while(thenCallBack = this.rejectedQueue.shift()){
typeof thenCallBack === 'function' && thenCallBack(error);
}
}
// 利用闭包 私有化 上述 属性 和方法
return ()=>{
if(this.promiseStatus !== 'pending') return; // promise的状态值 只能 由pending => fulfiled 或 pending => rejected,并且状态一旦更改,就不能再更改了。 所以此处将 非pending 状态的情况排除
this.promiseStatus = 'fulfiled'; //将状态 修改为 执行成功
if(value instanceof MyPromise){ //判断MyPromise 是否在value的原型链上, 存在说明 是MyPromise 构造出来的对象
/*
此处 需要做的操作就是 将传入的Promise 对象 执行完成之后再改变值,此时我们要使用到Promise的then方法确保传入的Promise 执行完成。我们下面就来实现 then方法
*/
value.then(res=>{
this.promiseValue = res;
runFulfilled(res);
},err=>{
this.promiseValue = err;
this.promiseStatus = 'rejected';// 失败 时 同时要将 Promise 状态进行更改
runRejected(err);
})
}else{ //非Promise 对象 直接修改
this.promiseValue = value;
}
}
}).call(this);
let mutation = new MutationObserver(run); //MutationObserver 具体用法可以自行百度
let element = document.createElement('span');
mutation.observer(element,{
attributes: true, childList: true, subtree: true
});
element.setAttribute('data','success'); //此处触发注册
}
// 同理 实现 reject
reject(value){
if(this.promiseStatus !== 'pending') return;
this.promiseStatus = 'rejected';
const run = (()=>{
let thenCallBack = '';
const runFulfilled = (value)=>{ //接收 resolve传入的 value值
while(thenCallBack = this.fulfilledQueue.shift()){ //每次都取出队列第一个then 回调 进行执行 直到所有then 方法的成功回调方法执行完成
typeof thenCallBack === 'function' && thenCallBack(value);
}
}
const runRejected = (error) =>{
while(thenCallBack = this.rejectedQueue.shift()){
typeof thenCallBack === 'function' && thenCallBack(error);
}
}
return ()=>{
if(this.promiseStatus !== 'pending') return; // promise的状态值 只能 由pending => fulfiled 或 pending => rejected,并且状态一旦更改,就不能再更改了。 所以此处将 非pending 状态的情况排除
this.promiseStatus = 'rejected'; //将状态 修改为 执行成功
if(value instanceof MyPromise){
this.promiseValue = value.then(res=>{//reject 方法 不依赖 传入的Promise 状态值所以此处即便传入的Prmise对象状态为 成功 也不修改当前Promise 状态,并且以传入的Promise对象作为当前Promise的值runRejected(res);
return res;
},err=>{
runRejected(err);
return err;
});
}else{
this.promiseValue = value;
runRejected(value);
}
}
}).call(this);
let mutation = new MutationObserver(run); //MutationObserver 具体用法可以自行百度
let element = document.createElement('span');
mutation.observer(element,{
attributes: true, childList: true, subtree: true
});
element.setAttribute('data','failing'); //此处触发注册
}
then(successCallBack,failCallBack){
return new MyPromise((newResolve,newReject)=>{ // 此处使用箭头函数 可以确保 this 该方法内 this 指向 调用 then 方法的 promise 对象
// 封装一个 执行成功的(resolve方法触发) 回调函数
const onFulfilled = value =>{
if(typeof successCallBack !== 'function'){
newResolve(value); //如果 then方法传入的参数不是函数 那么直接按上一个Promise 的值作为then方法返回新的Promise的值
}else{
//是函数 就直接执行,并且将执行结果(函数返回值) 作为 新的promise的value抛出
let result = successCallBack(value);
if(result instanceof MyPromise){ //如果返回值是一个promise 对象则需要等该promise执行完成(状态值不为pending),将执行完的结果作为 新的promise的value值
result.then(val=>{
newResolve(val);
},err=>{
newReject(err);
})
}else{
newResolve(result);
}
}
}
//封装一个 执行失败的 (reject方法触发) 回调函数
const onRejected = error =>{
if(typeof failCallBack !== 'function'){
newReject(error);
}else{
const result = failCallBack(error);
if(result instanceof MyPromise){
result.then(val=>{
newReject(val);
},err=>{
newReject(err);
})
}else{
newReject(error);
}
}
}
switch(this.promiseStatus){ // 根据promise 状态值来判断 执行相应的操作
case 'pending': //当状态为pending 时 将 上述函数 加入对应的 队列 等待被执行
this.fulfilledQueue.push(onFulfilled);
this.rejectedQueue.push(onRejected);
break;
case 'fulfilled':
onFulfilled(this.promiseValue);
break;
case 'rejected':
onRejected(this.promiseValue);
break;
}
})
}
}
- 再进行执行
执行顺序正常!!! 到此一个简易的promise 就实现了。