手写Promise
代码逐步迭代,可以对照着看,我把注释都写得比较清晰了~
构造函数实现
我们第一步首先就是完成Promise
的构造函数,构造函数我们简单去想,其实就是接收一个执行器函数,执行器函数有两个参数,这个方法阔以改变Promise
对象的状态和结果。ok,说干就干!
tips:
- 注意!throw err也可以修改Promise的状态与结果!
- promise的状态只能修改一次,需要做限制
// 万里长城第一步 function Promise(executor){ this.promiseState = 'pending'; this.promiseResult = null; const resolve = val => { // 状态只能修改一次 if(this.promiseState !== 'pending') return; // 1. 要去修改Promise对象的状态([[promiseState]]),置为成功fulfilled this.promiseState = 'fulfilled'; // 2. 要去修改Promise对象的状态([[promiseResult]]) this.promiseResult = val; } const reject = err => { // 状态只能修改一次 if(this.promiseState !== 'pending') return; // 1. 要去修改Promise对象的状态([[promiseState]]),置为失败rejected this.promiseState = 'rejected'; // 2. 要去修改Promise对象的状态([[promiseResult]]) this.promiseResult = err; } // 为什么要加try catch 是因为,throw err也相当于调用reject了【前面说过没看过的去补课】 try{ /* * 同步执行执行器函数 * 执行器函数接收两个参数,一个是resolve,一个是reject */ executor(resolve,reject); } catch(err) { reject(err); } }
then方法的实现
首先按照之前说过的,then支持两个参数,分别是成功和失败的回调,而且这两个参数可传可不传。
其次,因为异步任务的问题,并且支持多个回调,所以我们需要对回调函数采用数组进行存储,所以引入了新的变量,callbackList
而且我们需要注意then的返回结果也是Promise
对象【不记得的话,回头看看~】
// 万里长城今犹在~ function Promise(executor){ //保存promise状态 this.promiseState = 'pending'; //保存promise结果 this.promiseResult = null; //用于保存异步回调函数列表 this.callbackList = []; const resolve = val => { // 状态只能修改一次 if(this.promiseState !== 'pending') return; // 1. 要去修改Promise对象的状态([[promiseState]]),置为成功fulfilled this.promiseState = 'fulfilled'; // 2. 要去修改Promise对象的状态([[promiseResult]]) this.promiseResult = val; // 调用成功的回调【callbackList存起来的】 for(let callback of this.callbackList){ callback.onResolved(val); } } const reject = err => { // 状态只能修改一次 if(this.promiseState !== 'pending') return; // 1. 要去修改Promise对象的状态([[promiseState]]),置为失败rejected this.promiseState = 'rejected'; // 2. 要去修改Promise对象的状态([[promiseResult]]) this.promiseResult = err; // 调用失败的回调【callbackList存起来的】 for(let callback of this.callbackList){ callback.onRejected(err); } } // 为什么要加try catch 是因为,throw err也相当于调用reject了【前面说过没看过的去补课】 try{ /* * 同步执行执行器函数 * 执行器函数接收两个参数,一个是resolve,一个是reject */ executor(resolve,reject); } catch(err) { reject(err); } } //then方法 Promise.prototype.then = function(onResolved,onRejected){ const self = this; // then方法会返回Promise return new Promise((resolve,reject) => { // 对返回值的处理进行封装 const handleCallback = (callback) => { // 如果回调函数中抛出错误,则reject try{ // 需要依据回调的返回结果确定then方法的返回值 // 现在的this会指向return的promise对象,所以使用self const res = callback(self.promiseResult); if(res instanceof Promise){ //如果回调返回结果是个Promise res.then(val => { resolve(val); },err => { reject(err); }) }else{ // 返回结果不是Promise resolve(res); } }catch(err){ reject(err); } } //调用回调函数 if(this.promiseState === 'fulfilled'){ handleCallback(onResolved); } if(this.promiseState === 'rejected'){ handleCallback(onRejected); } /* * 如果是pending状态,则异步任务,在改变状态的时候去调用回调函数 * 所以要保存回调函数 * 因为promise实例阔以指定多个回调,于是采用数组 */ if(this.promiseState === 'pending'){ this.callbackList.push({ onResolved:() => { handleCallback(onResolved); }, onRejected:() => { handleCallback(onRejected); } }) } }) }
catch方法的实现
我们采用then方法去实现catch方法,但是catch可以处理异常穿透【前面又说哦~】
// 我想找人陪我去长城玩,哈哈哈哈 function Promise(executor){ //保存promise状态 this.promiseState = 'pending'; //保存promise结果 this.promiseResult = null; //用于保存异步回调函数列表 this.callbackList = []; const resolve = val => { // 状态只能修改一次 if(this.promiseState !== 'pending') return; // 1. 要去修改Promise对象的状态([[promiseState]]),置为成功fulfilled this.promiseState = 'fulfilled'; // 2. 要去修改Promise对象的状态([[promiseResult]]) this.promiseResult = val; // 调用成功的回调【callbackList存起来的】 for(let callback of this.callbackList){ callback.onResolved(val); } } const reject = err => { // 状态只能修改一次 if(this.promiseState !== 'pending') return; // 1. 要去修改Promise对象的状态([[promiseState]]),置为失败rejected this.promiseState = 'rejected'; // 2. 要去修改Promise对象的状态([[promiseResult]]) this.promiseResult = err; // 调用失败的回调【callbackList存起来的】 for(let callback of this.callbackList){ callback.onRejected(err); } } // 为什么要加try catch 是因为,throw err也相当于调用reject了【前面说过没看过的去补课】 try{ /* * 同步执行执行器函数 * 执行器函数接收两个参数,一个是resolve,一个是reject */ executor(resolve,reject); } catch(err) { reject(err); } } //then方法 Promise.prototype.then = function(onResolved,onRejected){ const self = this; //处理异常穿透 并且为onResolved,onRejected设置默认值。因为这两个参数可以都不传 if(typeof onRejected !== 'function'){ onRejected = err => { throw err; } } if(typeof onResolved !== 'function'){ onResolved = val => val; } // then方法会返回Promise return new Promise((resolve,reject) => { // 对返回值的处理进行封装 const handleCallback = (callback) => { // 如果回调函数中抛出错误,则reject try{ // 需要依据回调的返回结果确定then方法的返回值 // 现在的this会指向return的promise对象,所以使用self const res = callback(self.promiseResult); if(res instanceof Promise){ //如果回调返回结果是个Promise res.then(val => { resolve(val); },err => { reject(err); }) }else{ // 返回结果不是Promise resolve(res); } }catch(err){ reject(err); } } //调用回调函数 if(this.promiseState === 'fulfilled'){ handleCallback(onResolved); } if(this.promiseState === 'rejected'){ handleCallback(onRejected); } /* * 如果是pending状态,则异步任务,在改变状态的时候去调用回调函数 * 所以要保存回调函数 * 因为promise实例阔以指定多个回调,于是采用数组 */ if(this.promiseState === 'pending'){ this.callbackList.push({ onResolved:() => { handleCallback(onResolved); }, onRejected:() => { handleCallback(onRejected); } }) } }) } //catch方法 Promise.prototype.catch = function(onRejected) { // 我们可以直接使用then方法实现 return this.then(undefined,onRejected); }
Promise.resolve方法实现
简单了,不说啥了
//resolve方法 Promise.resolve = function(val) { //返回值的情况在前文说过,可以在 Promise的使用一章找到 return new Promise((resolve,reject)=>{ if(val instanceof Promise){ val.then(val => { resolve(val); }, err => { reject(err); }); }else{ resolve(value); } }) }
Promise.reject方法实现
更加简单了,不说啥了
//reject方法 Promise.reject = function(err) { //返回值的情况在前文说过,可以在 Promise的使用一章找到 return new Promise((resolve,reject)=>{ reject(err); }) }
Promise.all方法实现
比较简单,回顾之前Promise.all的用法以及返回值,就阔以看懂~
//可以先去回顾一下all方法的用法 //all Promise.all = function(promiseList) { let count = 0; let res = []; const length = promiseList.length; return new Promise((resolve,reject)=>{ for(let i = 0;i < length; i++){ promiseList[i].then(val => { count++; res[i] = val; if(count === length){ resolve(res); } },err => { reject(err); }); } }) }
Promise.race方法实现
比较简单,回顾之前Promise.race的用法以及返回值,就阔以看懂~
//race //要结束了! Promise.race = function(promiseList) { const length = promiseList.length; //谁先完成谁就决定结果! return new Promise((resolve,reject)=>{ for(let i = 0;i < length; i++){ promiseList[i].then(val => { resolve(val); },err => { reject(err); }); } }) }
完整代码以及细节处理
tips: 细节回调函数是异步的 我们使用setTimeout进行包裹
function Promise(executor){ //保存promise状态 this.promiseState = 'pending'; //保存promise结果 this.promiseResult = null; //用于保存异步回调函数列表 this.callbackList = []; const resolve = val => { // 状态只能修改一次 if(this.promiseState !== 'pending') return; // 1. 要去修改Promise对象的状态([[promiseState]]),置为成功fulfilled this.promiseState = 'fulfilled'; // 2. 要去修改Promise对象的状态([[promiseResult]]) this.promiseResult = val; setTimeout(() => { // 调用成功的回调【callbackList存起来的】 for(let callback of this.callbackList){ callback.onResolved(val); } }) } const reject = err => { // 状态只能修改一次 if(this.promiseState !== 'pending') return; // 1. 要去修改Promise对象的状态([[promiseState]]),置为失败rejected this.promiseState = 'rejected'; // 2. 要去修改Promise对象的状态([[promiseResult]]) this.promiseResult = err; setTimeout(() => { // 调用失败的回调【callbackList存起来的】 for(let callback of this.callbackList){ callback.onRejected(err); } }) } // 为什么要加try catch 是因为,throw err也相当于调用reject了【前面说过没看过的去补课】 try{ /* * 同步执行执行器函数 * 执行器函数接收两个参数,一个是resolve,一个是reject */ executor(resolve,reject); } catch(err) { reject(err); } } //then方法 Promise.prototype.then = function(onResolved,onRejected){ const self = this; //处理异常穿透 并且为onResolved,onRejected设置默认值。因为这两个参数可以都不传 if(typeof onRejected !== 'function'){ onRejected = err => { throw err; } } if(typeof onResolved !== 'function'){ onResolved = val => val; } // then方法会返回Promise return new Promise((resolve,reject) => { // 对返回值的处理进行封装 const handleCallback = (callback) => { // 如果回调函数中抛出错误,则reject try{ // 需要依据回调的返回结果确定then方法的返回值 // 现在的this会指向return的promise对象,所以使用self const res = callback(self.promiseResult); if(res instanceof Promise){ //如果回调返回结果是个Promise res.then(val => { resolve(val); },err => { reject(err); }) }else{ // 返回结果不是Promise resolve(res); } }catch(err){ reject(err); } } //调用回调函数 if(this.promiseState === 'fulfilled'){ setTimeout(()=>{ handleCallback(onResolved); }) } if(this.promiseState === 'rejected'){ setTimeout(()=>{ handleCallback(onRejected); }) } /* * 如果是pending状态,则异步任务,在改变状态的时候去调用回调函数 * 所以要保存回调函数 * 因为promise实例阔以指定多个回调,于是采用数组 */ if(this.promiseState === 'pending'){ this.callbackList.push({ onResolved:() => { handleCallback(onResolved); }, onRejected:() => { handleCallback(onRejected); } }) } }) } //catch方法 Promise.prototype.catch = function(onRejected) { // 我们可以直接使用then方法实现 return this.then(undefined,onRejected); } //resolve方法 Promise.resolve = function(val) { //返回值的情况在前文说过,可以在 Promise的使用一章找到 return new Promise((resolve,reject)=>{ if(val instanceof Promise){ val.then(val => { resolve(val); }, err => { reject(err); }); }else{ resolve(value); } }) } //reject方法 Promise.reject = function(err) { //返回值的情况在前文说过,可以在 Promise的使用一章找到 return new Promise((resolve,reject)=>{ reject(err); }) } //all Promise.all = function(promiseList) { let count = 0; let res = []; const length = promiseList.length; return new Promise((resolve,reject)=>{ for(let i = 0;i < length; i++){ promiseList[i].then(val => { count++; res[i] = val; if(count === length){ resolve(res); } },err => { reject(err); }); } }) } //race Promise.race = function(promiseList) { const length = promiseList.length; //谁先完成谁就决定结果! return new Promise((resolve,reject)=>{ for(let i = 0;i < length; i++){ promiseList[i].then(val => { resolve(val); },err => { reject(err); }); } }) }
至此,我们手写Promise的章节也就结束了~
结束语
tips:其实我真的很想吐槽自己,为什么老是在博客结尾要么打鸡血,要么说鸡汤,哈哈
Promise
一词本意是承诺。我以这篇文章作为我新的开始,从基础开始沉淀,拒绝好高骛远。
我承诺我的信念与追求会始终如一
我承诺会让自己看遍世间美景
我承诺我我会一直努力成为优秀的工程师
我承诺无论结果如何,喜欢的都会努力地勇敢地追求,不留遗憾
...
最后,愿老朽我永远热血,愿世界永远和平
伙伴们葱呀