手写Promise源码

1.Promise解决的问题

  • 回调嵌套,回调地狱

  • 错误捕获不好处理

  • 多个异步同步问题 Promise.all

2.版本问题

  • Promise是一个类,默认浏览器高版本或node都是自带Promise的

  • 如果低版本没有自带,我们可以使用es6-promise插件

3.promise A+规范

3.1 三个状态

  • Pending等待态

  • fulfilled成功态

  • rejected失败态

只有等待态才能变成成功态/失败态

如果状态变化,不能在修改状态

4.实现简单同步的Promise

 const PENDING = 'Pending'
 const SUCCESS = 'fulfilled'
 const FAIL = 'rejected'
 ​
 class Promise {
     constructor(executor){
         //初始化状态值为等待态
         this.status=PENDDING
         //在调用resolve或者reject时可能回传值
         this.value=undefined
         this.fail=undefined
         //成功态回调
         let resolve=(value)=>{
             //只有等待态才能修改状态值
             if(this.status===PENDDING){
                 this.status = SUCCESS
                 this.value=value
             }
         }
         //失败态回调
         const reject=(fail)=>{
             //只有等待态才能修改状态值
             if(this.status===PENDDING){
                 this.status= FAIL
                 this.fail=fail
             }
         }
         executor(resolve,reject)
     }
 ​
     then(fulfilled,rejected){
         //从等待态自己resolve方法
         if(this.status===SUCCESS){
             fulfilled(this.value)
         }
         //从等待态自己reject方法
         if(this.status===FAIL){
             rejected(this.fail)
         }
     }
 }
 ​
 module.exports=Promise

5.实现简单的异步Promise

  • 每个Promise的实例上都有then方法

  • Promise有多个状态如果成功会让成功的函数依次执行

  • 如果失败会让失败的函数依次执行

异步Promise,使用发布订阅模式

在等待态中,将所有的成功或者失败的回调都订阅存储到数组中,当状态从等待态变为成功态或者失败态时,遍历所有订阅的成功回调执行或者失败回调执行

 const PENDING = 'Pending'
 const SUCCESS = 'fulfilled'
 const FAIL = 'rejected'
 ​
 class Promise {
     constructor(executor){
         //初始化状态值为等待态
         this.status=PENDING
         //在调用resolve或者reject时可能回传值
         this.value=undefined
         this.fail=undefined
         //用来存储所有的成功,失败态
         this.onResolveCallback=[]
         this.onRejectCallbakc=[]
         //成功态回调
         let resolve=(value)=>{
             //只有等待态才能修改状态值
             if(this.status===PENDING){
                 this.status = SUCCESS
                 this.value=value
                 //发布所有订阅的消息
                 this.onResolveCallback.forEach(fn=>fn())
             }
         }
         //失败态回调
         const reject=(fail)=>{
             //只有等待态才能修改状态值
             if(this.status===PENDING){
                 this.status= FAIL
                 this.fail=fail
                 //发布所有订阅的消息
                 this.onRejectCallbakc.forEach(fn=>fn())
             }
         }
         executor(resolve,reject)
     }
 ​
     then(fulfilled,rejected){
         //从等待态自己resolve方法
         if(this.status===SUCCESS){
             fulfilled(this.value)
         }
         //从等待态自己reject方法
         if(this.status===FAIL){
             rejected(this.fail)
         }
 ​
         if(this.status===PENDDING){
             console.log('pedding');
             //订阅所有的成功,失败态
             this.onResolveCallback.push(()=>fulfilled(this.value))
             this.onRejectCallbakc.push(()=>rejected(this.fail))
         }
     }
 }
 ​
 module.exports=Promise

6.链式调用

Promise的链式调用,其实质就是每次then返回一个新的Promise实例

 const PENDING = 'Pending'
 const SUCCESS = 'fulfilled'
 const FAIL = 'rejected'
 function resolvePromise(x, promise2, resolve, reject) {
     //如果x与promise相等就会出现自己调用自己
     if (x === promise2) {
         return reject(new
             TypeError('TypeError: Chaining cycle detected for promise #<Promise>'))
     }
     //为了防止别人写的promise同时调用成功和失败的方法
     let called
     //判断x是不是一个对象或者方法
     if (typeof x === 'function' || (typeof x === 'object' && x != null)) {
         //判断x是不是一个promise
         try {
             let then = x.then
             if (typeof then === 'function') {
                 then.call(x, y => {
                     if (called) return
                     called = true
                     resolvePromise(y, promise2, resolve, reject)
                 }, error => {
                     if (called) return
                     called = true
                     reject(error)
                 })
             } else {
                 resolve(x)
             }
         } catch (error) {
             if (called) return
             called = true
             reject(error)
         }
     } else {
         resolve(x)
     }
 ​
 }
 class Promise {
     constructor(executor) {
         //初始化状态值为等待态
         this.status = PENDING
         //在调用resolve或者reject时可能回传值
         this.value = undefined
         this.fail = undefined
         //用来存储所有的成功,失败态
         this.onResolveCallback = []
         this.onRejectCallback = []
         //成功态回调
         let resolve = (value) => {
             //只有等待态才能修改状态值
             if (this.status === PENDING) {
                 this.status = SUCCESS
                 this.value = value
                 //发布所有订阅的消息
                 this.onResolveCallback.forEach(fn => fn())
             }
         }
         //失败态回调
         const reject = (fail) => {
             //只有等待态才能修改状态值
             if (this.status === PENDING) {
                 this.status = FAIL
                 this.fail = fail
                 //发布所有订阅的消息
                 this.onRejectCallback.forEach(fn => fn())
             }
         }
         try {
             executor(resolve, reject)
         } catch (e) {
             reject(e)
         }
     }
 ​
     then(onFulfilled, onRejected) {
         //为了实现值得穿透
         //p.then().then().then(val => console.log(val))
         onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
         onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }
         //为了解决链式调用问题,每一次then后,返回值需要是一个Promise
         let promise2 = new Promise((resolve, reject) => {
             //从等待态自己resolve方法
             if (this.status === SUCCESS) {
                 //为了是传入的promise2不为null
                 setTimeout(() => {
                     try {
                         //如果返回的x仍然是一个Promise我们需要处理
                         let x = onFulfilled(this.value)
                         //处理x
                         resolvePromise(x, promise2, resolve, reject)
                     } catch (e) {
                         reject(e)
                     }
                 })
             }
             //从等待态自己reject方法
             if (this.status === FAIL) {
                 setTimeout(() => {
                     try {
                         let x = onRejected(this.fail)
                         resolvePromise(x, promise2, resolve, reject)
                     } catch (e) {
                         reject(e)
                     }
                 })
 ​
             }
 ​
             if (this.status === PENDING) {
                 // console.log('PENDING');
                 //订阅所有的成功,失败态
                 this.onResolveCallback.push(() => {
                     setTimeout(() => {
                         try {
                             let x = onFulfilled(this.value)
                             resolvePromise(x, promise2, resolve, reject)
                         } catch (e) {
                             reject(e)
                         }
                     })
                 })
                 this.onRejectCallback.push(() => {
                     setTimeout(() => {
                         try {
                             let x = onRejected(this.fail)
                             resolvePromise(x, promise2, resolve, reject)
                         } catch (e) {
                             reject(e)
                         }
                     })
                 })
             }
         })
         return promise2
     }
 }
 ​
 //测试写的库是否合格promises-aplus-tests
 Promise.defer = Promise.deferred = function () {
     let dfd = {}
     dfd.promise = new Promise((resolve, reject) => {
         dfd.resolve = resolve
         dfd.reject = reject
     })
     return dfd
 }
 module.exports = Promise

7.resolve的是Promise

resolve中传递的是一个Promise实例,需要等待这个promise执行完成,在调用后续的then方法,因此需要在源码中判断resolve携带的参数是不是promise,如果是promise,需要执行传递的这个promise.then方法,进行递归调用,直到最后返回.then的最终结果

 const p=new Promise((resolve,reject)=>{
     resolve(new Promise((resolve,reject)=>{
         setTimeout(()=>{
             resolve(111)
         },2000)
     }))
 })
 p.then(data=>console.log(data))
 const p=new Promise((resolve,reject)=>{
     resolve(new Promise((resolve,reject)=>{
         resolve(new Promise((resolve,reject)=>{
             resolve(new Promise((resolve,reject)=>{
                 setTimeout(()=>{
                     resolve(111)
                 },2000)
             }))
         }))
     }))
 })
 p.then(data=>console.log(data))

源码修改:

在constructor构造函数中,对resolve方法传递的value值进行判断

 constructor(executor) {
         //初始化状态值为等待态
         this.status = PENDING
         //在调用resolve或者reject时可能回传值
         this.value = undefined
         this.fail = undefined
         //用来存储所有的成功,失败态
         this.onResolveCallback = []
         this.onRejectCallback = []
         //成功态回调
         let resolve = (value) => {
             //如果resolve里面传递的是一个promise
             if(value instanceof Promise){//判断value是 Promise的实例对象
                 return value.then(resolve,reject)
             }
             //只有等待态才能修改状态值
             if (this.status === PENDING) {
                 this.status = SUCCESS
                 this.value = value
                 //发布所有订阅的消息
                 this.onResolveCallback.forEach(fn => fn())
             }
         }
         //失败态回调
         const reject = (fail) => {
             //只有等待态才能修改状态值
             if (this.status === PENDING) {
                 this.status = FAIL
                 this.fail = fail
                 //发布所有订阅的消息
                 this.onRejectCallback.forEach(fn => fn())
             }
         }
         try {
             executor(resolve, reject)
         } catch (e) {
             reject(e)
         }
     }

8.catch

catch方法是then的语法糖

 catch(onRejected){
     return this.then(null,onRejected)
 }

9.finally

finally不管promise走的是resolve还是reject都会调用finally

 Promise.resolve=function(callback){
     return new Promise((resolve)=>{
         resolve(callback)
     })
 }
 ​
 Promise.reject=function(callback){
     return new Promise((resolve,reject)=>{
         reject(callback)
     })
 }
 ​
 //finally里面要使用resolve是因为要等待callback()执行完成,在执行后续的then方法
 Promise.prototype.finally=function(callback){
     return this.then(data=>{
         return Promise.resolve(callback()).then(()=>data)
     },err=>{//这里不能使用Promise.reject,因为如果使用了reject,那么就不会等待callback方法执行
         return Promise.resolve(callback()).then(()=>err)
     })
 }

10.all

异步同步 让所有的异步 并发执行 有序输出

 const fs=require('fs').promises
 Promise.all([fs.readFile('./name.txt','utf8'),fs.readFile('./age.txt','utf8'),3,4]).then(data=>console.log(data))

Promise源码修改

多个异步并发,解决办法计数器

 //判断是否是Promise
 function isPromise(value){
     if(typeof value ==='function' || (typeof value==='object' && value!=null)){
         if(typeof value.then==='function'){
             return true
         }
     }
     return false
 }
 Promise.all=function(values){
     return new Promise((resolve,reject)=>{
         let arr=[]
         //计数器,用于计数是否执行完成所有的任务
         let num=0
         //将返回的值以下标的形式存起来
         processData =(key,value)=>{
             arr[key]=value
             if(++num===values.length){
                 resolve(arr)
             }
         }
         for(let i=0;i<values.length;i++){
             let current=values[i]
             if(isPromise(current)){
                 current.then(x=>{
                     processData (i,x)
                 },reject)
             }else{
                 processData(i,current)
             }
         }
     })
 }

11.race

第一个成功就成功,输入第一个结果,第一个失败就失败

 Promise.race=function(values){
     return new Promise((resolve,reject)=>{
         for(let i=0;i<values.length;i++){
             let current=values[i]
             if(isPromise(current)){
                 current.then(resolve,reject)
             }else{
                 resolve(current)
             }
         }
     })
 }

面试题:中断Promise

 //中断Promise
 let p = new Promise((resolve, reject) => {
     setTimeout(() => {
         resolve()
     }, 3000)
 })
 ​
 function wrap(promise) {
     let about
     let newPromise = new Promise((resolve, reject) => {
         about = reject
     })
     let p = Promise.race([newPromise, promise])
     p.about = about
     return p
 }
 ​
 let p1 = wrap(p)
 ​
 setTimeout(() => {
     console.log('中断操作')
     p1.about('err')
 }, 2000)
 ​
 p1.then((value) => {
     console.log('没中断走这个')
 },err=>{
     console.log(err)
 })

12.Promise简单实现源码

 const PENDING = 'Pending'
 const SUCCESS = 'fulfilled'
 const FAIL = 'rejected'
 function resolvePromise(x, promise2, resolve, reject) {
     //如果x与promise相等就会出现自己调用自己
     if (x === promise2) {
         return reject(new
             TypeError('TypeError: Chaining cycle detected for promise #<Promise>'))
     }
     //为了防止别人写的promise同时调用成功和失败的方法
     let called
     //判断x是不是一个对象或者方法
     if (typeof x === 'function' || (typeof x === 'object' && x != null)) {
         //判断x是不是一个promise
         try {
             let then = x.then
             if (typeof then === 'function') {
                 then.call(x, y => {
                     if (called) return
                     called = true
                     resolvePromise(y, promise2, resolve, reject)
                 }, error => {
                     if (called) return
                     called = true
                     reject(error)
                 })
             } else {
                 resolve(x)
             }
         } catch (error) {
             if (called) return
             called = true
             reject(error)
         }
     } else {
         resolve(x)
     }
 ​
 }
 class Promise {
     constructor(executor) {
         //初始化状态值为等待态
         this.status = PENDING
         //在调用resolve或者reject时可能回传值
         this.value = undefined
         this.fail = undefined
         //用来存储所有的成功,失败态
         this.onResolveCallback = []
         this.onRejectCallback = []
         //成功态回调
         let resolve = (value) => {
             //如果resolve里面传递的是一个promise
             if(value instanceof Promise){//判断value是 Promise的实例对象
                 return value.then(resolve,reject)
             }
             //只有等待态才能修改状态值
             if (this.status === PENDING) {
                 this.status = SUCCESS
                 this.value = value
                 //发布所有订阅的消息
                 this.onResolveCallback.forEach(fn => fn())
             }
         }
         //失败态回调
         const reject = (fail) => {
             //只有等待态才能修改状态值
             if (this.status === PENDING) {
                 this.status = FAIL
                 this.fail = fail
                 //发布所有订阅的消息
                 this.onRejectCallback.forEach(fn => fn())
             }
         }
         try {
             executor(resolve, reject)
         } catch (e) {
             reject(e)
         }
     }
 ​
     catch(onRejected){
         return this.then(null,onRejected)
     }
 ​
     then(onFulfilled, onRejected) {
         //为了实现值得穿透
         //p.then().then().then(val => console.log(val))
         onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
         onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }
         //为了解决链式调用问题,每一次then后,返回值需要是一个Promise
         let promise2 = new Promise((resolve, reject) => {
             //从等待态自己resolve方法
             if (this.status === SUCCESS) {
                 //为了是传入的promise2不为null
                 setTimeout(() => {
                     try {
                         //如果返回的x仍然是一个Promise我们需要处理
                         let x = onFulfilled(this.value)
                         //处理x
                         resolvePromise(x, promise2, resolve, reject)
                     } catch (e) {
                         reject(e)
                     }
                 })
             }
             //从等待态自己reject方法
             if (this.status === FAIL) {
                 setTimeout(() => {
                     try {
                         let x = onRejected(this.fail)
                         resolvePromise(x, promise2, resolve, reject)
                     } catch (e) {
                         reject(e)
                     }
                 })
 ​
             }
 ​
             if (this.status === PENDING) {
                 // console.log('PENDING');
                 //订阅所有的成功,失败态
                 this.onResolveCallback.push(() => {
                     setTimeout(() => {
                         try {
                             let x = onFulfilled(this.value)
                             resolvePromise(x, promise2, resolve, reject)
                         } catch (e) {
                             reject(e)
                         }
                     })
                 })
                 this.onRejectCallback.push(() => {
                     setTimeout(() => {
                         try {
                             let x = onRejected(this.fail)
                             resolvePromise(x, promise2, resolve, reject)
                         } catch (e) {
                             reject(e)
                         }
                     })
                 })
             }
         })
         return promise2
     }
 }
 ​
 Promise.resolve=function(callback){
     return new Promise((resolve)=>{
         resolve(callback)
     })
 }
 ​
 Promise.reject=function(callback){
     return new Promise((resolve,reject)=>{
         reject(callback)
     })
 }
 ​
 //finally里面要使用resolve是因为要等待callback()执行完成,在执行后续的then方法
 Promise.prototype.finally=function(callback){
     return this.then(data=>{
         return Promise.resolve(callback()).then(()=>data)
     },err=>{//这里不能使用Promise.reject,因为如果使用了reject,那么就不会等待callback方法执行
         return Promise.resolve(callback()).then(()=>err)
     })
 }
 ​
 //判断是否是Promise
 function isPromise(value){
     if(typeof value ==='function' || (typeof value==='object' && value!=null)){
         if(typeof value.then==='function'){
             return true
         }
     }
     return false
 }
 Promise.all=function(values){
     return new Promise((resolve,reject)=>{
         let arr=[]
         //计数器,用于计数是否执行完成所有的任务
         let num=0
         //将返回的值以下标的形式存起来
         processData =(key,value)=>{
             arr[key]=value
             if(++num===values.length){
                 resolve(arr)
             }
         }
         for(let i=0;i<values.length;i++){
             let current=values[i]
             if(isPromise(current)){
                 current.then(x=>{
                     processData (i,x)
                 },reject)
             }else{
                 processData(i,current)
             }
         }
     })
 }
 ​
 Promise.race=function(values){
     return new Promise((resolve,reject)=>{
         for(let i=0;i<values.length;i++){
             let current=values[i]
             if(isPromise(current)){
                 current.then(resolve,reject)
             }else{
                 resolve(current)
             }
         }
     })
 }
 ​
 //测试写的库是否合格promises-aplus-tests
 Promise.defer = Promise.deferred = function () {
     let dfd = {}
     dfd.promise = new Promise((resolve, reject) => {
         dfd.resolve = resolve
         dfd.reject = reject
     })
     return dfd
 }
 module.exports = Promise