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


    前言

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

    在这里插入图片描述

    一、构造函数编写

    步骤

    1、定义一个TestPromise类,
    2、添加构造函数,
    3、定义resolve/reject,
    4、执行回调函数
    
    • 1
    • 2
    • 3
    • 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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    在这里插入图片描述

    二、promise的状态和原因

    分析

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

    步骤

    1、添加状态(pending / fulfilled / rejected)
    2、添加原因
    3、调整resolve/reject
    4、状态不可逆
    
    • 1
    • 2
    • 3
    • 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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    在这里插入图片描述

    三、then方法

    分析

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

    步骤一:成功和失败回调

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

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

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    步骤二:异步和多次调用

    1、定义实例属性(pending状态下保存then保存的回调函数)
    2、执行保存的成功和失败回调
    
    • 1
    • 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)
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    解析:当定义类存在setTimeout时,这时的state属性为pending,then执行了
    (所以我们要在then方法中加保存当前回调函数,当倒计时结束,调取resolve时我们执行回调函数数组)
    
    • 1
    • 2

    四、异步任务

    在这里插入图片描述

    分析

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

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

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

    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)
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    五、链式编程

    分析

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

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

    then方法中新建一个promise实例 获取返回值 处理异常
    
    • 1
    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)
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    处理思路:
    1、拿到返回值、判断是不是promise实例
    2、调去这个promise实例的then方法就可以了
    
    • 1
    • 2
    • 3
    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
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    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))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

    思路:对promise进行比较、并抛出异常
    
    • 1
    if (this.state === FULFILLED) {
      runAsynctask(() => {
        try {
          const x = onFulfilled(this.result)
          // 1. 处理重复引用
          if (x === p2) {
            // console.log('返回了p2')
            // 2. 抛出错误 Chaining cycle detected for promise #
            throw new TypeError('Chaining cycle detected for promise #')
          }
          if (x instanceof TestPromise) {
            x.then(res => resolve(res), err => reject(err))
          } else {
            resolve(x)
          }
        } catch (error) {
          reject(error)
        }
      })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    4、rejected状态

    抽取公共方法处理promise和重复调用
    
    • 1
    //  抽取函数
        function resolvePromise(p2, x, resolve, reject) {
          if (x === p2) {
            throw new TypeError('Chaining cycle detected for promise #')
          }
          if (x instanceof TestPromise) {
            x.then(res => resolve(res), err => reject(err))
          } else {
            resolve(x)
          }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    处理返回值

    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)
                            }
                        })
                    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    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)
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    六、实例方法-catch -finally

    实例方法-catch

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

    // catch是什么? 是语法糖!!!
    new Promise(() => {
    }).catch(() => {
    })
    // 等同于
    new Promise(() => {
    }).then(null, () => {
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    那么这个实力方法时处理以下两点
    	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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    实现:

    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)
            }
          }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    实例方法-finally

    以下时官网promise对finnally的介绍

    在这里插入图片描述

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

    /**
    * finally方法
     * 1. 内部调用then方法
     * */
    finally(onFinally) {
        return this.then(onFinally, onFinally)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

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

    静态方法-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)
         })
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    测试

     // ------------- 测试代码 手写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)
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    静态方法-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)
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    静态方法-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) })
             })
         })
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    注意:因为返回时一个promise对象,所以 promises.forEach数组遍历中,
    最快的一个会调用resolve或reject,
    只要其中一个执行,promises对象便不会在执行其他的
    
    • 1
    • 2
    • 3
    // ------------- 测试代码 手写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)
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    静态方法-all

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

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

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

     /**
      * 静态方法-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)
     })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    静态方法-allSettled

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

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

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

    /**
        * 静态方法-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)
     })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    静态方法-any

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

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

    实现
    在这里插入图片描述

     /**
      * 静态方法-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)
     })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    在这里插入图片描述

  • 相关阅读:
    Qt官方示例:Qt Quick Controls - Gallery
    E055-web安全应用-File Inclusion文件包含漏洞初级
    【BOOST C++ 5 】通信(03 网络编程 )
    栈(顺序栈)实现Language C
    MySql事务
    小白学java
    小白学安全-KunLun-M静态白盒扫描工具
    线程简单知识点
    “热帖”统计
    Exch:完整性检查 Database Integrity Checking
  • 原文地址:https://blog.csdn.net/weixin_43909743/article/details/133934660