Promise详解:手写Promise底层-实现Promise所有的功能和方法

前言

	目标:
		封装一个promise,更好的理解promise底层逻辑
	需求:
		实现以下promise所有的功能和方法 如下图所示

在这里插入图片描述

一、构造函数编写

步骤

1、定义一个TestPromise类,
2、添加构造函数,
3、定义resolve/reject,
4、执行回调函数
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>手写Promise</title>
</head>

<body>
  <h2>构造函数</h2>
  <script>
    // 1. 定义类
    class TestPromise{
         // 2. 添加构造函数
        constructor(func){
            // 3、声明 resolve reject
            const resolve = (result)=>{
                // TODO
                console.log("resolve",result)
            }
            const reject = (result)=>{
                // TODO
                console.log("reject",result)
            }
             // 4. 执行回调函数
            func(resolve,reject)
        } 
    }
    // ------------- 测试代码 -------------
    const p = new TestPromise((resolve, reject) => {
        console.log("调用了")
        resolve('success')
        //   reject('error')
    })
  </script>
</body>

</html>

在这里插入图片描述

二、promise的状态和原因

分析

promise有pending->fulfilled pending->rejected,
所以我们要为我们的实例类添加状态以及导致状态变化的原因
state状态 result原因
而且当pending状态一旦发生变化,便不可逆

步骤

1、添加状态(pending / fulfilled / rejected)
2、添加原因
3、调整resolve/reject
4、状态不可逆
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>手写Promise</title>
</head>

<body>
  <h2>构造函数</h2>
  <script>
    // 通过变量保存状态,便于后续使用
    const PENDING = 'pending'
    const FULFILLED = 'fulfilled'
    const REJECTED = 'rejected'
    class TestPromise{
         // 1. 添加状态(pending / fulfilled / rejected)
         state = PENDING
         // 2. 添加原因
         result = undefined
        constructor(func){
            // 改状态: pending->fulfilled
            // 记录原因
            const resolve = (result)=>{
                // 加判断状态不可逆
                if(this.state===PENDING){
                    this.state = FULFILLED
                    this.result = result
                }
            }
            // 改状态: pending->rejected
            // 记录原因
            const reject = (result)=>{
                if(this.state===PENDING){
                    this.state = REJECTED
                    this.result = result
                }
            }
            func(resolve,reject)
        } 
    }
    // ------------- 测试代码 -------------
    const p = new TestPromise((resolve, reject) => {
        resolve("fulfilled")
        // 只会执行上面的 状态变成fulfilled后下面不再执行
        reject("rejected")
    })
  </script>
</body>

</html>

在这里插入图片描述

三、then方法

分析

promise有成功和失败回调,异步多次调用

步骤一:成功和失败回调

1、添加实例方法
2、参数判断,判断传入的是不是回调函数
3、根据状态执行不同的回调函数(成功or失败)

注意如果传入的不是函数,成功和失败的回调默认实现是不同的,以下是文档,我们参考文档实现
在这里插入图片描述

class TestPromise{
         ···
        constructor(func){
            ···
        }
        // 1、添加实例方法
        then(onFulfilled, onRejected){
            // 2、参数判断,判断传入的是不是回调函数
            // 是函数返回函数,不是返回原值
            onFulfilled = typeof onFulfilled === 'function'?onFulfilled:x=>x
            // 是函数返回函数,不是抛出
            onRejected = typeof onRejected === 'function'?onRejected:x=>{ throw x}
            // 3、根据状态执行不同的回调函数(成功or失败)
            if(this.state === FULFILLED){
                onFulfilled(this.result)
            }else if(this.state === REJECTED){
                onRejected(this.result)
            }
        }
    }

	// ------------- 测试代码 -------------
	···
	p.then(res=>{
        console.log('成功回调',res)
    }, err=>{
        console.log('失败回调',err)
    })

步骤二:异步和多次调用

1、定义实例属性(pending状态下保存then保存的回调函数)
2、执行保存的成功和失败回调
class TestPromise{
         ···
         // 1、对象数组保存成功和失败的回调函数{onFulfilled, onRejected} 
         // # 定义属性私有,只有内部可以访问到
         #handlers = [] 
        constructor(func){
            const resolve = (result)=>{
                if(this.state===PENDING){
                    this.state = FULFILLED
                    this.result = result
                    // 3、执行成功的回调
                    this.#handlers.forEach(({onFulfilled})=>{
                        onFulfilled(this.result)
                    })
                }
            }
            const reject = (result)=>{
                if(this.state===PENDING){
                    this.state = REJECTED
                    this.result = result
                    // 3、执行失败的回调
                    this.#handlers.forEach(({onRejected})=>{
                        onRejected(this.result)
                    })
                }
            }
            func(resolve,reject)
        }
        then(onFulfilled, onRejected){
            onFulfilled = typeof onFulfilled === 'function'?onFulfilled:x=>x
            onRejected = typeof onRejected === 'function'?onRejected:x=>{ throw x}
            if(this.state === FULFILLED){
                onFulfilled(this.result)
            }else if(this.state === REJECTED){
                onRejected(this.result)
            }else if(this.state === PENDING){
            	// 2、保存回调函数
                this.#handlers.push({onFulfilled, onRejected})
            }
        }
    }
    // ------------- 测试代码 -------------
    const p = new TestPromise((resolve, reject) => {
    	// 异步
        setTimeout(()=>{
            resolve("fulfilled")
            // reject("rejected")
        },2000)
    })
    p.then(res=>{
        console.log('then1',res)
    }, err=>{
        console.log('then1',err)
    })
    p.then(res=>{
        console.log('then2',res)
    }, err=>{
        console.log('then2',err)
    })
解析:当定义类存在setTimeout时,这时的state属性为pending,then执行了
(所以我们要在then方法中加保存当前回调函数,当倒计时结束,调取resolve时我们执行回调函数数组)

四、异步任务

在这里插入图片描述

分析

promise.then()里面执行的是异步任务
所以我们的promise中也要实现异步处理,实现{
	1、核心API
	2、函数封装
}
核心API,vue2中执行异步的API有Promise.then、MutationObserver、setImmediate、setTimeout
选用queueMicrotask、MutationObserver、setTimeout
queueMicrotask:直接执行一个异步任务(node11开始支持、支持新式浏览器、IE不支持)
MutationObserver:dom节点改变执行异步任务(IE11支持)
setTimeout都支持
// 使用
queueMicrotask((fun)=>{
	fun() // 回调函数直接异步执行
})
const obs = new MutationObserver(()=>{
	// ...
})
const divNode = document.createElement('div')
// 参数一:观察的dom节点 参数二:观察的选项 childList观察子节点
obs.observe(divNode, { childList: true }) // 检测子节点是否改变
divNode.innerText = 'tets' // 开始修改子节点
// 节点发生改变执行异步回调

基于核心API完成异步任务的函数封装

1、定义函数,接收一个回调函数
2、调用核心api(queueMicrotask,MutationObserver,setTimeout)
3、在我们的promise调用封装的函数

1、定义函数,接收一个回调函数

// 1、定义函数
    function runAsynctask(callback){
        // 2. 调用核心api(queueMicrotask,MutationObserver,setTimeout)
        if(typeof queueMicrotask === 'function'){
            queueMicrotask(callback)
        }else if(typeof MutationObserver === 'function'){
            const obs = new MutationObserver(callback)
            const divNode = document.createElement('div')
            obs.observe(divNode, { childList: true })
            // 不需要把节点添加到页面
            divNode.innerText = 'test'
        }else{
            setTimeout(callback,0)
        }
    }

2、在我们的promise调用封装的函数

	class TestPromise{
		···
        then(onFulfilled, onRejected){
            onFulfilled = typeof onFulfilled === 'function'?onFulfilled:x=>x
            onRejected = typeof onRejected === 'function'?onRejected:x=>{ throw x}
            if(this.state === FULFILLED){
+++             runAsynctask(()=>{
                    onFulfilled(this.result)
                })
            }else if(this.state === REJECTED){
+++             runAsynctask(()=>{
                    onRejected(this.result)
                })
            }else if(this.state === PENDING){
                this.#handlers.push({onFulfilled:()=>{
+++                 runAsynctask(()=>{
                        onFulfilled(this.result)
                    })
                }, onRejected:()=>{
+++                 runAsynctask(()=>{
                        onRejected(this.result)
                    })
                }})
            }
        }
    }
    // ------------- 测试代码 -------------
    console.log(1)
    const p = new TestPromise((resolve, reject) => {
        console.log(2)
        resolve(3)
        // reject("rejected")
    })
    p.then(res=>{
        console.log(res)
    })
    console.log(4)

五、链式编程

分析

promise.then().then()
promise可以一直then方法
核心:
1、then方法需要返回是支持.then调用的(promise实例)
2、根据 pending、fulfilled、rejected三种状态支持链式编程
3、在这个promise实例获取上一个then的返回值并处理
	{
		1、处理返回值
		2、处理异常
		3、处理返回promise
		4、处理重复引用
	}

1、处理返回值和处理异常

then方法中新建一个promise实例 获取返回值 处理异常
then(onFulfilled, onRejected){
     onFulfilled = typeof onFulfilled === 'function'?onFulfilled:x=>x
     onRejected = typeof onRejected === 'function'?onRejected:x=>{ throw x}
     // 1. 返回新Promise实例
     const p2 = new TestPromise((resolve, reject) => {
         if (this.state === FULFILLED) {
             runAsynctask(() => {
                 // 2. 获取返回值
                 try {
                     const x = onFulfilled(this.result)
                     //    2.1 处理返回值
                     resolve(x)
                 } catch (error) {
                     //    2.2 处理异常
                     console.log('捕获异常', error)
                     reject(error)
                 }
                 
                 
             })
         } else if (this.state === REJECTED) {
             runAsynctask(() => {
                 onRejected(this.result)
             })
         } else if(this.state === PENDING){
             this.#handlers.push({onFulfilled:()=>{
                 runAsynctask(()=>{
                     onFulfilled(this.result)
                 })
             }, onRejected:()=>{
                 runAsynctask(()=>{
                     onRejected(this.result)
                 })
             }})
         }
     })
     return p2
 }
 // ------------- 测试代码 -------------
    const p = new TestPromise((resolve, reject) => {
        resolve("resolve")
        // reject("rejected")
    })
    p.then(res=>{
        console.log(res)
        // throw 'throw error'
        return 2
    }).then(res=>{
        console.log(res)
    },err=>{
        console.log(err)
    })

2、处理返回promise

如果promise.then()里面返回依旧是一个promise,这个时候需要怎么处理?

const p = new TestPromise((resolve, reject) => {
      resolve(1)
    })
    p.then(res => {
      return new TestPromise((resolve, reject) => {
        resolve(2)
        // reject('error')
      })
    }).then(res => {
      console.log('p2:', res) // 2
    }, err => {
      console.log('p2:', err) // err
    })
处理思路:
1、拿到返回值、判断是不是promise实例
2、调去这个promise实例的then方法就可以了
class TestPromise{
		···
        then(onFulfilled, onRejected){
           ···
            const p2 = new TestPromise((resolve, reject) => {
                if (this.state === FULFILLED) {
                    runAsynctask(() => {
                        try {
                            const x = onFulfilled(this.result)
                            // 1.处理返回Promise
  +++                      if (x instanceof TestPromise) {
                                // 2. 调用then方法
                                // x.then(res => console.log(res), err => console.log(err))
+++                           x.then(res => resolve(res), err => reject(err))
                            } else {
                                resolve(x)
                            }
                        } catch (error) {
                            console.log('捕获异常', error)
                            reject(error)
                        }
                        
                        
                    })
                } else if (this.state === REJECTED) {
                    ···
                } else if(this.state === PENDING){
                    ···
                }
            })
            return p2
        }
    }

3、处理返回promise重复调用

 const p = new Promise((resolve, reject) => {
        resolve("resolve")
    })
    const p2 = p.then(res=>{
        // throw 'throw error'
       	return p2
    })
    p2.then(res=>{},err=>console.log('err:', err))

原生的promise会有重复调用的错误提示
在这里插入图片描述

思路:对promise进行比较、并抛出异常
if (this.state === FULFILLED) {
  runAsynctask(() => {
    try {
      const x = onFulfilled(this.result)
      // 1. 处理重复引用
      if (x === p2) {
        // console.log('返回了p2')
        // 2. 抛出错误 Chaining cycle detected for promise #<Promise>
        throw new TypeError('Chaining cycle detected for promise #<Promise>')
      }
      if (x instanceof TestPromise) {
        x.then(res => resolve(res), err => reject(err))
      } else {
        resolve(x)
      }
    } catch (error) {
      reject(error)
    }
  })

4、rejected状态

抽取公共方法处理promise和重复调用
//  抽取函数
    function resolvePromise(p2, x, resolve, reject) {
      if (x === p2) {
        throw new TypeError('Chaining cycle detected for promise #<Promise>')
      }
      if (x instanceof TestPromise) {
        x.then(res => resolve(res), err => reject(err))
      } else {
        resolve(x)
      }
    }

处理返回值

const p2 = new TestPromise((resolve, reject) => {
                if (this.state === FULFILLED) {
                    runAsynctask(() => {
                        try {
                            // 获取返回值
                            const x = onFulfilled(this.result)
                            resolvePromise(p2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                        
                        
                    })
                } else if (this.state === REJECTED) {
                    runAsynctask(() => {
                        // 1、处理异常
+++                     try {
                            // 获取返回值
+++                       const x = onRejected(this.result)
                            resolvePromise(p2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    })
                }

5、pending状态

 } else if(this.state === PENDING){
       this.#handlers.push({onFulfilled:()=>{
           runAsynctask(()=>{
               try {
                   // 获取返回值
                   const x = onFulfilled(this.result)
                   resolvePromise(p2, x, resolve, reject)
               } catch (error) {
                   reject(error)
               } 
           })
       }, onRejected:()=>{
           runAsynctask(()=>{
               try {
                   // 获取返回值
                   const x = onRejected(this.result)
                   resolvePromise(p2, x, resolve, reject)
               } catch (error) {
                   reject(error)
               }
           })
       }})
   }

···
	// ------------- 测试代码 -------------
	const p = new TestPromise((resolve, reject) => {
        setTimeout(() => {
            resolve("resolve")
        }, 2000);
    })
    const p2 = p.then(res => {
        throw 'error'
        // return p2
        // return 2
        //   return new TestPromise((resolve, reject) => {
        //     reject('Promise-error')
        //   })
    })
    p2.then(res=>{
        return console.log('err:', err)
    }, err => {
      console.log('p2-err:', err)
    })

六、实例方法-catch -finally

实例方法-catch

我们先看下官网对catch的讲述
在这里插入图片描述
由此我们可以得出:

// catch是什么? 是语法糖!!!
new Promise(() => {
}).catch(() => {
})
// 等同于
new Promise(() => {
}).then(null, () => {
})
那么这个实力方法时处理以下两点
	1、then中没有写err函数
	const p = new TestPromise((resolve, reject) => {
      reject('reject-error')
    })
    p.then(res => {
      console.log('res:', res)
    }).catch(err => {
      console.log('err:', err)
    })


2、创建函数时的异常 没有resolve reject
const p = new TestPromise((resolve, reject) => {
      throw 'throw-error'
    })

实现:

1、在类then方法下面新建catch方法
/**
* catch方法
   * 1. 内部调用then方法
   * */
  catch(onRejected) {
    // 1. 内部调用then方法
    return this.then(undefined, onRejected)
  }
  2、在constructor构造函数中 处理异常
  constructor(func) {
        // pending->fulfilled
        const resolve = (result) => {
          if (this.state === PENDING) {
            this.state = FULFILLED
            this.result = result
            this.#handlers.forEach(({ onFulfilled }) => {
              onFulfilled(this.result)
            })
          }
        }

        // pending->rejected
        const reject = (result) => {
          if (this.state === PENDING) {
            this.state = REJECTED
            this.result = result
            this.#handlers.forEach(({ onRejected }) => {
              onRejected(this.result)
            })
          }
        }

        // 2. 处理异常
+++    try {
          func(resolve, reject)
        } catch (error) {
          // console.log('error:', error)
          reject(error)
        }
      }

实例方法-finally

以下时官网promise对finnally的介绍

在这里插入图片描述

在这里插入图片描述
由此可知,其内部调取then(onFinally, onFinally)

/**
* finally方法
 * 1. 内部调用then方法
 * */
finally(onFinally) {
    return this.then(onFinally, onFinally)
}

七、静态方法-resolve -reject-race-all-allSettled-any

注意:静态的是指向类自身,而不是指向实例对象,主要是归属不同,这是静态属性,静态方法的核心
也就是说类可以访问到,但实例对象访问不到、继承类也可以访问到

静态方法-resolve

官网介绍:
在这里插入图片描述
由此可知:resolve是把一个值转换为promise实例,如果本身就是promise实例那么直接返回
在这里插入图片描述
实现:

/**
  * 静态方法-resolve
  *  1. 判断传入值
  *  2.1 Promise直接返回
  *  2.2 转为Promise并返回(fulfilled状态)
  * */
 static resolve(value) {
     // 1. 判断传入值
     if (value instanceof TestPromise) {
         // 2.1 Promise直接返回
         return value
     }
     // 2.2 转为Promise并返回(fulfilled状态)
     return new TestPromise((resolve) => {
         resolve(value)
     })
 }

测试

 // ------------- 测试代码 手写Promise  -------------
    TestPromise.resolve(new TestPromise((resolve, reject) => {
      resolve('resolve')
      // reject('reject')
      // throw 'error'
    })).then(res => {
      console.log('res:', res)
    }, err => {
      console.log('err:', err)
    })

    TestPromise.resolve('hahah').then(res => {
      console.log(res)
    })

静态方法-reject

在这里插入图片描述
由此可知静态方法-reject为传递一个reject的promise对象,实现:

	/**
       * 静态方法-reject
       * 1. 返回rejected状态的Promise
       * */
      static reject(value) {
        // 1. 返回rejected状态的Promise
        return new TestPromise((undefined, reject) => {
          reject(value)
        })
      }
// 测试:
// ------------- 测试代码 手写Promise  -------------
    TestPromise.reject('error').catch(res => {
      console.log(res)
    })

静态方法-race

在这里插入图片描述
从官网可知,race接收一个promise对象数组,返回第一个最快执行完的promise,无论它是rejected还是fuilled
注意:如果传递的不是promise,会把值默认转换成promise对象,并执行resolve
注意:如果是传递的不是数组,会报以下错误
在这里插入图片描述

/**
 * 静态方法-race
  * 1. 返回Promise
  * 2. 判断是否为数组 错误信息:Argument is not iterable
  * 3. 等待第一个敲定
  * */
 static race(promises) {
     // 1. 返回Promise
     return new TestPromise((resolve, reject) => {
         // 2. 判断是否为数组
         if (!Array.isArray(promises)) {
             return reject(new TypeError('Argument is not iterable'))
         }
         // 3. 等待第一个敲定
         promises.forEach(p => {
             // p.then
             TestPromise.resolve(p).then(res => { resolve(res) }, err => { reject(err) })
         })
     })
 }
注意:因为返回时一个promise对象,所以 promises.forEach数组遍历中,
最快的一个会调用resolve或reject,
只要其中一个执行,promises对象便不会在执行其他的
// ------------- 测试代码 手写Promise  -------------
    const p1 = new TestPromise((resolve, reject) => {
      setTimeout(() => {
        resolve(1)
      }, 1000)
    })
    const p2 = new TestPromise((resolve, reject) => {
      setTimeout(() => {
        reject(2)
      }, 2000)
    })

    // TestPromise.race([p1, p2]).then((res) => {
      TestPromise.race([p1, p2, 'hahah']).then((res) => {
      // TestPromise.race().then((res) => {
      console.log('res:', res)
    }, err => {
      console.log('err:', err)
    })

静态方法-all

分析:
在这里插入图片描述

promise.all([promise1,promise2,promise3])
all方法接收一个promise数组,
如果都是resolve 并返回传入数组顺序的promise的res数组
当有rejected时,返回第一个rejected

思路:
在这里插入图片描述

 /**
  * 静态方法-all
  *  1. 返回Promise实例
  *  2. 判断是否为数组 错误信息:Argument is not iterable
  *  3. 空数组直接兑现
  *  4. 处理全部兑现
  *    4.1 记录结果
  *    4.2 判断全部兑现
  *  5. 处理第一个拒绝
  * */
 static all(promises){
     // 1. 返回Promise
     return new TestPromise((resolve, reject) => {
         // 2. 判断是否为数组
         if (!Array.isArray(promises)) {
             return reject(new TypeError('Argument is not iterable'))
         }
         // 3. 空数组直接兑现
         promises.length === 0 && resolve(promises)
         // 4. 处理全部兑现 
         // 思路(promise异步执行顺序,返回数组和原来的传入数组顺序可能不同索引 
         // 所以我们可以根据传入数组的索引值对最终数组进行数组排序)
         // 4.1 记录结果
         const results = []
         let count = 0
         promises.forEach((p, index)=>{
             TestPromise.resolve(p).then(res=>{
                 results[index] = res
                 // 4.2 判断全部兑现
                 // 为什么不能用 results.length进行判断,因为如果第一个执行完返回的是第三项results[3] = res 当前数组情况是[ , , res]
                 // 我们用count次数进行判断
                 count++
                 count===promises.length && resolve(results)


             }, err=>{
                 // 5. 处理第一个拒绝
                 reject(err)
             })
         })

         
     })
 }
 // ------------- 测试代码 手写Promise  -------------
 const p1 = TestPromise.resolve(1)
 const p2 = new TestPromise((resolve, reject) => {
   setTimeout(() => {
     resolve(2)
     // reject('error')
   }, 1000)
 })
 const p3 = 3
 const p4 = new TestPromise((resolve, reject) => {
   setTimeout(() => {
     // resolve(4)
     reject('error-1234')
   }, 2000)
 })

 TestPromise.all([p1, p2, p3, p4]).then(res => {
 // TestPromise.all().then(res => {
 //   TestPromise.all([]).then(res => {
   console.log('res:', res)
 }, err => {
   console.log('err:', err)
 })

静态方法-allSettled

分析:
在这里插入图片描述
我们promise测试一下
在这里插入图片描述

由此发现:它和all方法类似,依旧是等待所有的promise敲定返回,顺序也是传入顺序,
但不是第一个rejected抛出,而是全部执行完后以 status:fulfilled,value:value返回resolve,以status:rejected,reason:value返回rejected的数组

实现:
在这里插入图片描述

/**
    * 静态方法-allSettled
    * 1. 返回Promise
    * 2. 数组判断 错误信息: Argument is not iterable
    * 3. 为空直接敲定
    * 4. 等待全部敲定
    *  4.1 记录结果
    *  4.2 处理兑现{status:'fulfilled',value:''}
    *  4.3 处理拒绝{status:'rejected',reason:''}
    * */
 static allSettled(promises) {
   // 1. 返回Promise
   return new TestPromise((resolve, reject) => {
     // 2. 数组判断
     if (!Array.isArray(promises)) {
       return reject(new TypeError('Argument is not iterable'))
     }
     // 3. 为空直接敲定
     promises.length === 0 && resolve(promises)

     // 4. 等待全部敲定
     // 4.1 记录结果
     const results = []
     let count = 0
     promises.forEach((p, index) => {
       TestPromise.resolve(p).then(res => {
         // 4.2 处理兑现{status:'fulfilled',value:''}
         results[index] = { status: FULFILLED, value: res }
         count++
         count === promises.length && resolve(results)
       }, err => {
         // 4.3 处理拒绝{status:'rejected',reason:''}
         results[index] = { status: REJECTED, reason: err }
         count++
         count === promises.length && resolve(results)
       })
     })
   })
 }
// ------------- 测试代码 手写Promise -------------
 const p1 = TestPromise.resolve(1)
 const p2 = 2
 const p3 = new TestPromise((resolve, reject) => {
   setTimeout(() => {
     reject(3)
   }, 1000)
 })
 TestPromise.allSettled([p1, p2, p3]).then(res => {
   // TestPromise.allSettled().then(res => {
   // TestPromise.allSettled([]).then(res => {
   console.log('res:', res)
 }, err => {
   console.log('err:', err)
 })

静态方法-any

在这里插入图片描述
在这里插入图片描述

由此可知,any是接收一个promise数组(可以是常量),如果存在一个成功,则直接返回第一个成功的resolve
如果没有成功的,则返回所有的拒绝原因(与传入顺序一致)
注意:空值和空数组都会报错

实现
在这里插入图片描述

 /**
  * 静态方法-any
  * 1. 返回Promise,数组判断 错误信息: Argument is not iterable
  * 2. 空数组直接拒绝 AggregateError([错误原因1..],All promises were rejected)
  * 3. 等待结果
  *  3.1 第一个兑现
  *  3.2 全部拒绝
  */
 static any(promises) {
     // 1. 返回Promise,数组判断
     return new TestPromise((resolve, reject) => {
     if (!Array.isArray(promises)) {
         return reject(new TypeError('Argument is not iterable'))
     }
     // 2. 空数组直接拒绝
     promises.length === 0 && reject(new AggregateError(promises, 'All promises were rejected'))

     // 3. 等待结果
     const errors = []
     let count = 0
     promises.forEach((p, index) => {
         TestPromise.resolve(p).then(res => {
         // 3.1 第一个兑现
         resolve(res)
         }, err => {
         // 3.2 全部拒绝
         errors[index] = err
         count++
         count === promises.length && reject(new AggregateError(errors, 'All promises were rejected'))
         })
     })
     })
 }
// ------------- 测试代码 手写Promise -------------
 const p1 = new TestPromise((resolve, reject) => {
   setTimeout(() => {
     reject(1)
   }, 2000)
 })
 // const p2 = 2
 const p2 = TestPromise.reject(2)
 const p3 = new TestPromise((resolve, reject) => {
   setTimeout(() => {
     // resolve(3)
     reject(3)
   }, 1000)
 })

 TestPromise.any([p1, p2, p3]).then(res => {
   // TestPromise.any().then(res => {
   // TestPromise.any([]).then(res => {
   console.log('res:', res)
 }, err => {
   console.dir(err)
 })

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值