# 手写promise

Promise 其实就是一个构造函数,可以使用这个构造函数创建一个 Promise 实例。

该构造函数很简单,它只有一个参数,按照 Promise/A+ 规范的命名,把 Promise 构造函数的参数叫做 executor,executor 类型为函数。这个函数又「自动」具有 resolve、reject 两个方法作为参数。

  1. 创建Promise函数
function Promise(executor) {

}

避免微信小程序请求的回调地狱,可以自己封装一个wxRequest对象:

wxRequest('./userInfo')
 .then(
   data => wxRequest(`./${data.id}/friendList`),
   error => {
     console.log(error)
   }
 )
 .then(
   data => {
     console.log(data)
   },
   error => {
     console.log(error)
   }
 )

Promise 构造函数返回一个 promise 对象实例,这个返回的 promise 对象具有一个 then 方法。then 方法中,调用者可以定义两个参数,分别是 onfulfilledonrejected,它们都是函数类型。其中 onfulfilled 通过参数,可以获取 promise 对象 resolved 的值,onrejected 获得 promise 对象 rejected 的值。通过这个值,我们来处理异步完成后的逻辑。

  1. 完善promise
function Promise(executor) {

}

Promise.prototype.then = function(onfulfilled, onrejected) {

}

看promise例子:

let promise1 = new Promise((resolve, reject) => {
 resolve('data')
})

promise1.then(data => {
 console.log(data)
})

let promise2 = new Promise((resolve, reject) => {
 reject('error')
})

promise2.then(data => {
 console.log(data)
}, error => {
 console.log(error)
})

在使用 new 关键字调用 Promise 构造函数时,在合适的时机(往往是异步结束时),调用 executor 的参数 resolve 方法,并将 resolved 的值作为 resolve 函数参数执行,这个值便可以后续在 then 方法第一个函数参数(onfulfilled)中拿到;同理,在出现错误时,调用 executor 的参数 reject 方法,并将错误信息作为 reject 函数参数执行,这个错误信息可以在后续的 then 方法第二个函数参数(onrejected)中拿到。

因此,在实现 Promise 时,应该有两个值,分别储存 resolved 的值,以及 rejected 的值(当然,因为 Promise 状态的唯一性,不可能同时出现 resolved 的值和 rejected 的值,因此也可以用一个变量来存储);同时也需要存在一个状态,这个状态就是 promise 实例的状态(pending,fulfilled,rejected);同时还要提供 resolve 方法以及 reject 方法,这两个方法需要作为 executor 的参数提供给开发者使用:

  1. 添加resolve reject方法,同时添加存取成功失败值的两个变量(如果创建的函数是用箭头函数,那么就不需要self)
function Promise(executor) {
 const self = this
 this.status = 'pending'
 this.value = null
 this.reason = null

 function resolve(value) {
   self.value = value
 }

 function reject(reason) {
   self.reason = reason
 }

 executor(resolve, reject)
}

Promise.prototype.then = function(onfulfilled = Function.prototype, onrejected = Function.prototype) {
 onfulfilled(this.value)
 onrejected(this.reason)
}

当promise的状态发生变化,是不可逆的!所以还是要处理。

  1. 不可以同时执行多个resolve/reject
//promiseA+
function Promise(executor){
	this.value = null
	this.reason = null
	this.status = 'pending'
	const resolve = data=>{
		if(this.status === 'pending'){
			this.value =data
			this.status ='fulfilled'
		}
		
	}
	const reject = reason=>{
		if(this.status === 'pending'){
			this.reason =reason
			this.status ='rejected'
		}
		
	}
	executor(resolve,reject)
}

Promise.prototype.then =function(onfulfilled,onrejected){
	onfulfilled = typeof onfulfilled === 'function' ? onfulfilled : data =>data
	onrejected = typeof onrejected === 'function' ? onrejected :error=>{throw error}
	if(this.status === 'fulfilled'){
		onfulfilled(this.value)
	}
	if(this.status === 'rejected'){
		onrejected(this.reason)
	}
}
  1. 异步操作处理:应该是开发者调用 resolve 的时刻,那么先在状态(status)为 pending 时,把开发者传进来的 onfulfilled 方法存起来,在 resolve 方法中再去执行即可。
//promiseA+
function Promise(executor){
	this.value = null
	this.reason = null
	this.status = 'pending'
	this.onFulfilledFunc = Function.prototype
	this.onRejectedFunc = Function.prototype
	const resolve = data=>{
		if(this.status === 'pending'){
			this.value =data
			this.status ='fulfilled'
			console.log(this.status)
			this.onFulfilledFunc(this.value)
		}
		
	}
	const reject = reason=>{
		if(this.status === 'pending'){
			this.reason =reason
			this.status ='rejected'
			console.log(this.status)
			this.onRejectedFunc(this.reason)
		}
		
	}
	executor(resolve,reject)
}

Promise.prototype.then =function(onfulfilled,onrejected){
	console.log(onfulfilled)
	onfulfilled = typeof onfulfilled === 'function' ? onfulfilled : data =>data
	onrejected = typeof onrejected === 'function' ? onrejected :error=>{throw error}
	if(this.status === 'fulfilled'){
		onfulfilled(this.value)
	}
	if(this.status === 'rejected'){
		onrejected(this.reason)
	}
	
	if(this.status === 'pending'){
		console.log(this.status)
		this.onFulfilledFunc = onfulfilled
		this.onRejectedFunc = onrejected
	}
}

let promise = new Promise((resolve, reject) => {
 setTimeout(() => {
   resolve('data')
 },2000)
})

promise.then(data => {
 console.log(data)
})
  1. 同步代码优先异步/回调执行,同时在 resolve 方法中,加入了对 value 值是一个 Promise 实例的判断
//promiseA+
function Promise(executor){
	this.value = null
	this.reason = null
	this.status = 'pending'
	this.onFulfilledFunc = Function.prototype
	this.onRejectedFunc = Function.prototype
	const resolve = data=>{
		if(data instanceof Promise){
			return data.then(resolve,reject)
		}
		setTimeout(()=>{
			if(this.status === 'pending'){
				this.value =data
				this.status ='fulfilled'
				this.onFulfilledFunc(this.value)
			}
		})
		
		
	}
	const reject = reason=>{
		setTimeout(()=>{
			if(this.status === 'pending'){
				this.reason =reason
				this.status ='rejected'
				this.onRejectedFunc(this.reason)
			}
		})
			
	}
	executor(resolve,reject)
}

Promise.prototype.then =function(onfulfilled,onrejected){
	onfulfilled = typeof onfulfilled === 'function' ? onfulfilled : data =>data
	onrejected = typeof onrejected === 'function' ? onrejected :error=>{throw error}
	if(this.status === 'fulfilled'){
		onfulfilled(this.value)
	}
	if(this.status === 'rejected'){
		onrejected(this.reason)
	}
	
	if(this.status === 'pending'){
		this.onFulfilledFunc = onfulfilled
		this.onRejectedFunc = onrejected
	}
}
  • 此时的项目还存在问题,两个promise调用只会去触发第二个,而第一个则被覆盖了
let promise = new Promise((resolve, reject) => {
 setTimeout(() => {
   resolve('data')
 }, 2000)
})

promise.then(data => {
 console.log(`1: ${data}`)
})
promise.then(data => {
 console.log(`2: ${data}`)
})

//2: data
  1. 解决覆盖问题:只需要将所有 then 方法中的 onFulfilledFunc 储存为一个数组 onFulfilledArray,在 resolve 时,依次执行即可。对于 onRejectedFunc 同理;同时对executor函数做个trycatch处理。
//promiseA+
function Promise(executor){
	this.value = null
	this.reason = null
	this.status = 'pending'
	this.onFulfilledArray = []
	this.onRejectedArray =[]
	const resolve = data=>{
		if(data instanceof Promise){
			return data.then(resolve,reject)
		}
		setTimeout(()=>{
			if(this.status === 'pending'){
				this.value =data
				this.status ='fulfilled'
				// this.onFulfilledFunc(this.value)
				this.onFulfilledArray.forEach(func=>{
					func(this.value)
				})
			}
		})
		
		
	}
	const reject = reason=>{
		setTimeout(()=>{
			if(this.status === 'pending'){
				this.reason =reason
				this.status ='rejected'
				// this.onRejectedFunc(this.reason)
				this.onRejectedArray.forEach(func=>{
					func(this.reason)
				})
			}
		})
			
	}
	try {
	 executor(resolve, reject)
	} catch(e) {
	 reject(e)
	}
}

Promise.prototype.then =function(onfulfilled,onrejected){
	onfulfilled = typeof onfulfilled === 'function' ? onfulfilled : data =>data
	onrejected = typeof onrejected === 'function' ? onrejected :error=>{throw error}
	if(this.status === 'fulfilled'){
		cosnole.log(11)
		onfulfilled(this.value)
	}
	if(this.status === 'rejected'){
		onrejected(this.reason)
	}
	
	if(this.status === 'pending'){
		// this.onFulfilledFunc = onfulfilled
		this.onFulfilledArray.push(onfulfilled)
		// this.onRejectedFunc = onrejected
		this.onRejectedArray.push(onrejected)
	}
}

let promise = new Promise((resolve, reject) => {
 // setTimeout(() => {
   resolve('data')
 // }, 2000)
})

promise.then(data => {
 console.log(`1: ${data}`)
})
promise.then(data => {
 console.log(`2: ${data}`)
})
promise.then(data => {
 console.log(`2: ${data}`)
})
promise.then(data => {
 console.log(`3: ${data}`)
})

一个 Promise 实例的 then 方法体 onfulfilled 函数和 onrejected 函数中,是支持再次返回一个 Promise 实例的,也支持返回一个非 Promise 实例的普通值;并且返回的这个 Promise 实例或者这个非 Promise 实例的普通值将会传给下一个 then 方法 onfulfilled 函数或者 onrejected 函数中,这样就支持链式调用了。

  1. promise的链式调用实现:
	function Promise(executor){
		this.status = 'pending'
		this.value = null
		this.reason = null
		
		// this.onfulfilledFunc = Function.prototype
		// this.onrejectedFunc = Function.prototype
		
		// promise 实例状态变更之前,添加多个 then 方法,所有的状态是一致的,所以可以用数组依次添加
		this.onfulfilledArray = []
		this.onrejectedArray = []
		
		const resolve = value => {
			// 这里的作用:如果value是Promise,则需要继续执行下一步
			if(value instanceof Promise){
				return value.then(resolve,reject)
			}
			setTimeout(()=>{
				if(this.status === 'pending'){
					this.value = value
					this.status = 'fulfilled'
					// this.onfulfilledFunc(this.value)
					console.log(this.onfulfilledArray)
					this.onfulfilledArray.forEach(func=>{
						func(this.value)
					})
				}
			})
			
		}
		const reject = reason =>{
			setTimeout(()=>{
				if(this.status === 'pending'){
					this.reason = reason
					this.status =  'rejected'
					// this.onrejectedFunc(this.reason)
					this.onrejectedArray.forEach(func=>{
						func(this.reason)
					})
				}
			})
		}
		try{
			executor(resolve,reject)
		}catch(e){
			reject(e)
			//TODO handle the exception
		}
	}
	
	Promise.prototype.then = function(onfulfilled,onrejected){
		
		onfulfilled = typeof onfulfilled === "function"?onfulfilled:data=>data
		onrejected = typeof onrejected === 'function'?onfulfilled:error=>{ throw error }
		let promise2 
		if(this.status === 'fulfilled'){
			console.log(this.status,'status')
			// onfulfilled(this.value)
			// 实现链式调用功能,需要返回一个promise
			return promise2 = new Promise((resolve,reject)=>{
				setTimeout(()=>{
					try{
						let result = onfulfilled(this.value)
						resolve(result)
					}catch(e){
						reject(e)
						//TODO handle the exception
					}
				})
			})
			
		}
		if(this.status === 'rejected'){
			// onrejected(this.reason)
			return  promise2 = new Promise((resolve,reject)=>{
				try{
					let result = onrejected(this.reason)
					resolve(result)
				}catch(e){
					reject(e)
					//TODO handle the exception
				}
			})
		}
		if(this.status === 'pending'){
			// console.log(this.status,'status')
			// this.onfulfilledFunc = onfulfilled
			// this.onrejectedFunc = onrejected
			
			// this.onfulfilledArray.push(onfulfilled)
			// this.onrejectedArray.push(onrejected)
			
			promise2 = new Promise((resolve,reject)=>{
				 this.onfulfilledArray.push(() => {
				   try {
					
					 let result = onfulfilled(this.value)
					 // 链式调用需要
					 resolve(result)
				   }
				   catch(e) {
					 reject(e)
				   }
				 })
			
				 this.onrejectedArray.push(() => {
				   try {
					 let result = onrejected(this.reason)
					 resolve(result)
				   }
				   catch(e) {
					 reject(e)
				   }
				 }) 
			})
			console.log(promise2)
			return promise2
		}
	}
	
	let promise = new Promise((resolve, reject) => {
	 setTimeout(() => {
	   resolve('data')
	 })
	})
	
	promise.then(data => {
	 console.log(`1: ${data}`)
	}).then(res=>{
		console.log(res)
		return 10000088
	}).then(res=>{
		console.log(res)
	}).then(res=>{
		console.log(res)
	})
	promise.then(data => {
	 console.log(`2: ${data}`)
	})


// 1. 状态只能变一次
// 2. 如果 resolve 异步执行,then 已经调用过,还在 pending 状态时,所以需要想办法在 resolve 执行时接住 onfulfilled/onrejected
// 3. Promise 是异步执行的,需要控制 resolve 和 reject 的执行时间
// 4.为了能够支持 then 方法的链式调用,那么每一个 then 方法的 onfulfilled 函数和 onrejected 函数都应该返回一个 Promise 实例。

# 完整范例1

class Promise{
  constructor(executor){
    this.state = 'pending';
    this.value = undefined;
    this.reason = undefined;
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];
    let resolve = value => {
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
        this.onResolvedCallbacks.forEach(fn=>fn());
      }
    };
    let reject = reason => {
      if (this.state === 'pending') {
        this.state = 'rejected';
        this.reason = reason;
        this.onRejectedCallbacks.forEach(fn=>fn());
      }
    };
    try{
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }
  then(onFulfilled,onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
    let promise2 = new Promise((resolve, reject) => {
      if (this.state === 'fulfilled') {
        setTimeout(() => {
          try {
            let x = onFulfilled(this.value);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      };
      if (this.state === 'rejected') {
        setTimeout(() => {
          try {
            let x = onRejected(this.reason);
            resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      };
      if (this.state === 'pending') {
        this.onResolvedCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onFulfilled(this.value);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              let x = onRejected(this.reason);
              resolvePromise(promise2, x, resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0)
        });
      };
    });
    return promise2;
  }
  catch(fn){
    return this.then(null,fn);
  }
}
function resolvePromise(promise2, x, resolve, reject){
  if(x === promise2){
    return reject(new TypeError('Chaining cycle detected for promise'));
  }
  let called;
  if (x != null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      let then = x.then;
      if (typeof then === 'function') { 
        then.call(x, y => {
          if(called)return;
          called = true;
          resolvePromise(promise2, y, resolve, reject);
        }, err => {
          if(called)return;
          called = true;
          reject(err);
        })
      } else {
        resolve(x);
      }
    } catch (e) {
      if(called)return;
      called = true;
      reject(e); 
    }
  } else {
    resolve(x);
  }
}
//resolve方法
Promise.resolve = function(val){
  return new Promise((resolve,reject)=>{
    resolve(val)
  });
}
//reject方法
Promise.reject = function(val){
  return new Promise((resolve,reject)=>{
    reject(val)
  });
}
//race方法 
Promise.race = function(promises){
  return new Promise((resolve,reject)=>{
    for(let i=0;i<promises.length;i++){
      promises[i].then(resolve,reject)
    };
  })
}
//all方法(获取所有的promise,都执行then,把结果放到数组,一起返回)
Promise.all = function(promises){
  let arr = [];
  let i = 0;
  function processData(index,data){
    arr[index] = data;
    i++;
    if(i == promises.length){
      resolve(arr);
    };
  };
  return new Promise((resolve,reject)=>{
    for(let i=0;i<promises.length;i++){
      promises[i].then(data=>{
        processData(i,data);
      },reject);
    };
  });
}

# 完整范例2

class HD {
  static PENDING = 'pending'; // 准备
  static FUlFILLED = 'fulfilled'; // 解决
  static REJECTED = 'rejected'; // 拒绝
  constructor(executor) {
    this.status = HD.PENDING;
    this.value = null;
    this.callbacks = [];
    try {
      executor(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error);
    }
  }

  resolve(value) {
    // 异步特性
    if (this.status == HD.PENDING) {
      this.status = HD.FUlFILLED;
      this.value = value;
      // 让与resolve同块的方法先执行
      setTimeout(() => {
        // 处理准备时期 then 放入的回调
        this.callbacks.forEach(callback => {
          callback['onFulfilled'](value);
        })
      })
    }
  }

  reject(reason) {
    // 异步特性
    if (this.status == HD.PENDING) {
      this.status = HD.REJECTED;
      this.value = reason;
      // 让与resolve同块的方法先执行
      setTimeout(() => {
        // 处理准备时期 then 放入的回调
        this.callbacks.forEach(callback => {
          callback['onRejected'](reason);
        })
      })
    }
  }

  then(onFulfilled, onRejected) {
    // 没传resolve方法
    if (typeof onFulfilled != 'function') {
      // then值穿透
      onFulfilled = () => this.value;
    }
    // 没传reject方法
    if (typeof onRejected != 'function') {
      // 没有catch异常
      onRejected = function () {
        throw new Error("Unexpected end of input")
      }
    }
    let promise = new HD((resolve, reject) => {
      // 准备
      if (this.status == HD.PENDING) {
        this.callbacks.push({
          onFulfilled: value => {
            // 冗余代码的优化
            HD.parse(promise, onFulfilled(value), resolve, reject)
          },
          onRejected: reason => {
            // 冗余代码的优化
            HD.parse(promise, onRejected(reason), resolve, reject)
          }
        });
      }
      // 处理
      else if (this.status == HD.FUlFILLED) {
        // 等待this.next赋值
        setTimeout(() => {
          // 冗余代码的优化
          HD.parse(promise, onFulfilled(this.value), resolve, reject)
        })
      }
      // 拒绝
      else if (this.status == HD.REJECTED) {
        // 等待this.next赋值
        setTimeout(() => {
          // 冗余代码的优化
          HD.parse(promise, onRejected(this.value), resolve, reject)
        })
      }
    });

    return promise;
  }

  static parse(promise, result, resolve, reject) {
    // 禁止同一个then中循环返回 promise
	console.log(promise,result)
    if (promise == result) {
      throw new TypeError('Chaining cycle detected')
    }
    try {
      // 设置结果值
      if (result instanceof HD) {
        result.then(resolve, reject);
      } else {
        resolve(result);
      }
    } catch (error) {
      reject(error);
    }
  }

  static resolve(value) {
    return new HD((resolve, reject) => {
      HD.parse(null, value, resolve, reject);
    })
  }
  static reject(value) {
    return new HD((resolve, reject) => {
      reject(value)
    })
  }

  /**
   * 全成功,返回全部返回值
   * 有失败,返回第一个失败信息
   * @param {HD} promises 
   */
  static all(promises) {
    return new HD((resolve, reject) => {
      const values = [];
      promises.forEach((promise) => {
        promise.then(
          value => {
            values.push(value)
            if (values.length == promises.length) {
              resolve(values);
            }
          },
          reason => {
            reject(reason)
          }
        )
      })
    })
  }

  /**
   * race(竞赛)
   * 返回第一个返回值
   * @param {HD} promises 
   */
  static race(promises) {
    return new HD((resolve, reject) => {
      promises.forEach(promise => {
        promise.then(
          value => {
            return resolve(value);
          },
          reason => {
            return reject(reason);
          }
        )
      })
    })
  }
}

最后更新: 6/14/2022, 8:37:39 AM