当前位置 : 主页 > 网络编程 > JavaScript >

JavaScript手写Promise核心原理

来源:互联网 收集:自由互联 发布时间:2023-01-19
目录 准备 完善 resolve/reject then 异步处理 链式调用 边界处理 catch 优化后完整代码 准备 首先, promise 有三种状态: pending fulfilled rejected ; promise 在实例化操作中, 有两个改变状态的方法
目录
  • 准备
  • 完善 resolve/reject
  • then
    • 异步处理
    • 链式调用
    • 边界处理
  • catch
    • 优化后完整代码

      准备

      • 首先,promise 有三种状态:pending fulfilled rejected;
      • promise在实例化操作中, 有两个改变状态的方法,分别为resolve,reject;
      • promise有很多方法,详情请见 mdn, 本篇文章先实现 promise的核心apithencatch;

      我们使用 es6 提供的 class 来实现

      class MyPromise {
       // 准备三个状态
       static PENDING = 'pending';
       static FULFILLED = 'fulfilled';
       static REJECTED = 'rejected';
      
       constructor(executor) {
         this.status = MyPromise.PENDING; // 表示promise的状态
         this.value = null;  // 表示promise的值
         try {
           executor(this.resolve.bind(this), this.reject.bind(this))
         } catch (error) {
           this.reject(error)
         }
       }
       resolve() {
       }
       reject() {
       }
      }
      

      在这里 executor 就是传递过来的函数,可以接收 resolvereject,这里将内部的两个方法给传入,如果在调用的过程中报错了会调用reject方法

      完善 resolve/reject

      他们做的工作分为以下几部

      • 将状态改为pendingfulfilled 或 rejected
      • 可以接受一个值为当前的promisevalue
        resolve(value) {
          if (this.status === MyPromise.PENDING) {
            this.status = MyPromise.FULFILLED;
            this.value = value
          }
        }
        reject(value) {
          if (this.status === MyPromise.PENDING) {
            this.status = MyPromise.REJECTED;
            this.value = value
          }
        }
      

      then

      then 函数可以接受两个参数,分别为成功的回调函数和失败的回调函数,并且回调函数的默认为一个函数

      • 状态为 fulfilled 执行第一个回调,rejected 执行第二个回调
      • 回调函数中给传入当前的 value
      • then的执行为异步的
        then(onFulfilled, onRejected) {
          if (typeof onFulfilled !== 'function') {
            onFulfilled = value => value
          }
      
          if (typeof onFulfilled !== 'function') {
            onRejected = value => value
          }
      
          if (this.status === MyPromise.FULFILLED) {
            setTimeout(() => {
              onFulfilled(this.value)
            })
          }
      
          if (this.status === MyPromise.REJECTED) {
            setTimeout(() => {
              onRejected(this.value)
            })
          }
        }
      

      验证一下:

      console.log(1)
      new MyPromise((resolve, reject) => {
        console.log(2)
        resolve('成功')
      }).then(res => console.log(res))
      
      console.log(3)
      
      // 打印 1 2 3 成功
      

      promise里面有异步代码的时候,这个时候运行到.then方法 状态为pending,下来增加一下异步任务的处理

      异步处理

      当状态为pending的时候,表示执行的是异步任务,这个时候我们可以增加一个callback,把异步执行的内容添加到这个callback中,当执行完异步代码的时候,会执行异步函数的callback的任务

      constructor(executor) {
        // ...
        this.callbacks = []; // 用来存储回调函数的容器
        // ...
      }
      resolve(value) {
        // ...
        this.callbacks.forEach(({ onFulfilled }) => onFulfilled(value)) 
        // 当执行到这里的时候 如果有onFulfilled 就说明已经执行完then方法给容器添加内容了。把resolve的值传递给onFulfilled
      } 
      reject(value) {
        // ...
        this.callbacks.forEach(({ onRejected }) => onRejected(value))
        // 当执行到这里的时候 如果有onRejected 就说明已经执行完then方法给容器添加内容了。把reject的值传递给onFulfilled
      }
      then(onFulfilled, onRejected) {
        // ...
        if (this.status === MyPromise.PENDING) {
          this.callbacks.push({
            onFulfilled: value => {
              setTimeout(() => {
                onFulfilled(value)
              })
            },
            onRejected: value => {
              setTimeout(() => {
                onRejected(value)
              })
            }
          })
        }
       }
      

      验证一下:

      new MyPromise((resolve, reject) => {
        setTimeout(() => {
          resolve('成功')
        })
      }).then(res => console.log(res)) 
      
      // 打印  成功
      

      then 函数可以链式调用,接下来我们完善一下

      链式调用

      链式调用的核心就是返回一个新的 promise,当成功调用的时候调用新的promiseresolve,失败reject,并且链式调用会把前一个的返回值当作下一个的 resolve 的状态

      then(onFulfilled, onRejected) {
          if (typeof onFulfilled !== 'function') {
            onFulfilled = value => value
          }
      
          if (typeof onFulfilled !== 'function') {
            onRejected = value => value
          }
          return new MyPromise((resolve, reject) => {
            if (this.status === MyPromise.FULFILLED) {
              setTimeout(() => {
                const result = onFulfilled(this.value)
                resolve(result)
              })
            }
      
            if (this.status === MyPromise.REJECTED) {
              setTimeout(() => {
                const result = onRejected(this.value)
                resolve(result) 
              })
            }
            if (this.status === MyPromise.PENDING) {
              this.callbacks.push({
                onFulfilled: value => {
                  setTimeout(() => {
                    const result = onFulfilled(value)
                    resolve(result)
                  })
                },
                onRejected: value => {
                  setTimeout(() => {
                    const result = onRejected(value)
                    resolve(result)
                  })
                }
              })
            }
          })
        }

      验证一下:

      new MyPromise((resolve, reject) => {
        setTimeout(() => {
          reject('失败')
        })
      }).then(res => res, err => err).then(res => console.log(res))
      
      // 打印  失败
      

      如果.then的回调函数返回的是promise的情况也要做个处理

      边界处理

      实现前:

      new MyPromise((resolve, reject) => {
        setTimeout(() => {
          resolve('成功')
        })
      }).then(
        res => new MyPromise((resolve, reject) => {
          resolve(res)
        }),
        err => err
      ).then(res => console.log(res))
      
      // 打印  { "status": "fulfilled", "value": "成功", "callbacks": [] }
      

      当判断返回值为 MyPromise 的时候,需要手动调用 .then 的方法取他的值,并且吧当前的 promise 的改变状态的函数透出给 then 方法

        then(onFulfilled, onRejected) {
          if (typeof onFulfilled !== 'function') {
            onFulfilled = value => value
          }
      
          if (typeof onFulfilled !== 'function') {
            onRejected = value => value
          }
          return new MyPromise((resolve, reject) => {
            if (this.status === MyPromise.FULFILLED) {
              setTimeout(() => {
                const result = onFulfilled(this.value)
                if (result instanceof MyPromise) { 
                  result.then(resolve, reject)
                } else {
                  resolve(result)
                }
              })
            }
      
            if (this.status === MyPromise.REJECTED) {
              setTimeout(() => {
                const result = onRejected(this.value)
                if (result instanceof MyPromise) {
                  result.then(resolve, reject)
                } else {
                  resolve(result)
                }
              })
            }
      
            if (this.status === MyPromise.PENDING) {
              this.callbacks.push({
                onFulfilled: value => {
                  setTimeout(() => {
                    const result = onFulfilled(value)
                     if (result instanceof MyPromise) {
                       result.then(resolve, reject)
                     } else {
                      resolve(result)
                     }
                  })
                },
                onRejected: value => {
                  setTimeout(() => {
                    const result = onRejected(value)
                    if (result instanceof MyPromise) {
                      result.then(resolve, reject)
                    } else {
                      resolve(result)
                    }
                  })
                }
              })
            }
          })
        }
      

      验证:

      new MyPromise((resolve, reject) => {
        setTimeout(() => {
          resolve('成功')
        })
      }).then(
        res => new MyPromise((resolve, reject) => {
          resolve(res)
        }),
        err => err
      ).then(res => console.log(res))
      
      // 打印  成功
      
      

      到这里 .then 方法就实现差不多了,接下来实现 catch 方法

      catch

      catch 方法可以处理拒绝的状态和错误的状态:

        catch(onFulfilled) {
          if (typeof onFulfilled !== 'function') {
            onFulfilled = value => value
          }
      
          return new MyPromise((resolve, reject) => {
            if (this.status === MyPromise.REJECTED) {
              setTimeout(() => {
                const result = onFulfilled(this.value)
                if (result instanceof MyPromise) {
                  result.then(resolve, reject)
                } else {
                  resolve(result)
                }
              })
            }
          })
        }
      

      验证:

      new MyPromise((resolve, reject) => {
        reject('失败')
      }).catch(res=> console.log(res))
      
      // 打印  失败
      

      道理其实和 then 是相同的,到这里主功能基本上就差不多了,但是有很多重复的地方,优化一下

      优化后完整代码

      class MyPromise {
        // 准备三个状态
        static PENDING = 'pending';
        static FULFILLED = 'fulfilled';
        static REJECTED = 'rejected';
      
        constructor(executor) {
          this.status = MyPromise.PENDING; // 表示promise的状态
          this.value = null;  // 表示promise的值
          this.callbacks = [];
          try {
            executor(this.resolve.bind(this), this.reject.bind(this))
          } catch (error) {
            console.log(error)
            this.reject(error)
          }
        }
        resolve(value) {
          if (this.status === MyPromise.PENDING) {
            this.status = MyPromise.FULFILLED;
            this.value = value
          }
          this.callbacks.forEach(({ onFulfilled }) => onFulfilled(value))
        }
        reject(value) {
          if (this.status === MyPromise.PENDING) {
            this.status = MyPromise.REJECTED;
            this.value = value
          }
          this.callbacks.forEach(({ onRejected }) => onRejected(value))
        }
        parse({ callback, resolve, reject, value = this.value }) {
          setTimeout(() => {
            const result = callback(value)
            if (result instanceof MyPromise) {
              result.then(resolve, reject)
            } else {
              resolve(result)
            }
          })
        }
        then(onFulfilled, onRejected) {
          if (typeof onFulfilled !== 'function') {
            onFulfilled = value => value
          }
      
          if (typeof onFulfilled !== 'function') {
            onRejected = value => value
          }
          return new MyPromise((resolve, reject) => {
            if (this.status === MyPromise.FULFILLED) {
              this.parse({ callback: onFulfilled, resolve, reject })
            }
      
            if (this.status === MyPromise.REJECTED) {
              this.parse({ callback: onRejected, resolve, reject })
            }
      
            if (this.status === MyPromise.PENDING) {
              this.callbacks.push({
                onFulfilled: value => {
                  this.parse({ callback: onFulfilled, resolve, reject, value })
                },
                onRejected: value => {
                  this.parse({ callback: onRejected, resolve, reject, value })
                }
              })
            }
          })
        }
        catch(onFulfilled) {
          if (typeof onFulfilled !== 'function') {
            onFulfilled = value => value
          }
      
          return new MyPromise((resolve, reject) => {
            if (this.status === MyPromise.REJECTED) {
              this.parse({ callback: onFulfilled, resolve, reject })
            }
          })
        }
      }

      到此这篇关于JavaScript手写Promise核心原理的文章就介绍到这了,更多相关JavaScript Promise内容请搜索自由互联以前的文章或继续浏览下面的相关文章希望大家以后多多支持自由互联!

      网友评论