乐趣区

关于javascript:简单实现一个-Promise

如何实现一个 Promise/A+

Promise 应该具备什么属性?

  • A promise must be in one of three states: pending, fulfilled, or rejected[1].
  • 同时依据 promise 的三种状态,须要有两个属性用于存储 promise 的返回后果,value, reason
  • Promise 实例是一个 thenable 的对象,即必须蕴含一个 then 办法

    const PENDING = 'pending'
    const FULLFILLED = 'fulfilled'
    const REJECTED = 'rejected'
    
    class PbPromise{constructor(){
        this.state = PENDING
        this.value = undefined
        this.reason = null
      }
    
      then(){}
    }

如何实例化一个 Promise 实例

  • 通过 new Promise(fn)实例化一个 Promise 实例,其中 fn 用于扭转以后 Promsise 的状态, 即 Promsie 实例在实例化时须要承受一个函数类型的参数,executor,这个函数用于扭转以后 Promise 的状态。该函数是在 promise 实例化过程中同步执行的
  • 内部的函数如何扭转 Promsie 外部的状态?这须要 Promise与该函数产生交互,即须要Promise 提供扭转其状态的办法给 executor,因为Promise 会有两种状态的变动,因而该办法须要承受两个办法别离解决不同的状态 – executor(resolve, reject)
  const PENDING = 'pending'
  const FULLFILLED = 'fulfilled'
  const REJECTED = 'rejected'
  class PbPromise{constructor(executor){
      this.state = PENDING
      this.value = undefined
      this.reason = null
+      // 用于将以后 Promise 状态转换为 FULLFILLED
+      const resolve = () => {
+        // 状态只能转变一次
+        if(this.state !== PENDING) return 
+        this.state = FULLFILLED
+      }
+      // 用于将以后 Promise 状态转换为 REJECTED
+      const reject = () => {
+        // 状态只能转变一次
+        if(this.state !== PENDING) return 
+        this.state = REJECTED
+      }
+      // 此时内部通过 调用 resolve 或者 reject 就能够扭转 Promise 外部的状态
+      executor(resolve, reject)
    }

    then(){}
  }

then 办法进行回调接管

  • Promse 通过 then 预设 状态 (state) 发生变化之后的回调函数。then 承受两个函数作为参数:promise.then(onFulfilled, onRejected), 其中 onFulfilled 为 fulfilled 状态的回调,onRejected为 rejected 之后的回调。
  const PENDING = 'pending'
  const FULLFILLED = 'fulfilled'
  const REJECTED = 'rejected'

  class PbPromise{constructor(executor){
      this.state = PENDING
      this.value = undefined
      this.reason = null
+        this.onFulfilledList = []
+        this.onRejectedList = []

      // 用于将以后 Promise 状态转换为 FULLFILLED
      const resolve = value => {
        // 状态只能转变一次
        if(this.state !== PENDING) return 
        this.state = FULLFILLED
        this.value = value

+          // 状态发生变化 要 回调 then 存储的回调函数
+          this.onFulfilledList.forEach(f => f())
      }

      // 用于将以后 Promise 状态转换为 REJECTED
      const reject = reason => {
        // 状态只能转变一次
        if(this.state !== PENDING) return 
        this.state = REJECTED
        this.reason = reason

+          // 状态发生变化 要 回调 then 存储的回调函数
+          this.onRejectedList.forEach(f => f())
      }

      // 此时内部通过 调用 resolve 或者 reject 就能够扭转 Promise 外部的状态
      executor(resolve, reject)
    }

-      then(){-}
+      // 承受回调函数,并进行执行 / 存储
+      then(onFulfilled, onRejected){
+        // 查看以后状态,非 PENDING 间接执行回调函数
+        if(this.state === FULLFILLED){+          return onFulfilled(this.value)
+        }
+        if(this.state === REJECTED){+          return onRejected(this.reason)
+        }
+
+        // PENDING 状态须要将回调函数存储起来,此时须要两个列表来存储回调函数
+        // onFulfilledList onRejectedList
+        // 这些回调函数应该在 resolve 办法 或者 reject 办法调用之后立刻调用
+        this.onFulfilledList.push(onFulfilled)
+        this.onRejectedList.push(onRejected)
    }
  }
  • then 办法要返回一个新的 Promise,用于实现链式调用,新的Promsie 的状态要在 以后 then 中传入的回调函数执行时变动,用于保障 then 之间回调函数的执行程序
  class PbPromise{constructor(executor){
      this.state = PENDING
      this.value = undefined
      this.reason = null
      this.onFulfilledList = []
      this.onRejectedList = []

      // 用于将以后 Promise 状态转换为 FULLFILLED
      const resolve = value => {
        // 状态只能转变一次
        if(this.state !== PENDING) return 
        this.state = FULLFILLED
        this.value = value

        // 状态发生变化 要 回调 then 存储的回调函数
        this.onFulfilledList.forEach(f => f())
      }

      // 用于将以后 Promise 状态转换为 REJECTED
      const reject = reason => {
        // 状态只能转变一次
        if(this.state !== PENDING) return 
        this.state = REJECTED
        this.reason = reason

        // 状态发生变化 要 回调 then 存储的回调函数
        this.onRejectedList.forEach(f => f())
      }

      // 此时内部通过 调用 resolve 或者 reject 就能够扭转 Promise 外部的状态
      executor(resolve, reject)
    }

    // 承受回调函数,并进行执行 / 存储
    then(onFulfilled, onRejected){+        return new PbPromise((resolve, reject) => {
        // 查看以后状态,非 PENDING 间接执行回调函数
        if(this.state === FULLFILLED){-          return onFulfilled(this.value)
+          const value = onFulfilled(this.value)
+          return resolve(value)
        }
        if(this.state === REJECTED){-            return onRejected(this.reason)
+            const reason = onRejected(this.reason)
+            // 留神这里是 resove
+            return resolve(reason)
        }

        // PENDING 状态须要将回调函数存储起来,此时须要两个列表来存储回调函数
        // onFulfilledList onRejectedList
        // 这些回调函数应该在 resolve 办法 或者 reject 办法调用之后立刻调用
-         this.onFulfilledList.push(onFulfilled)
-         this.onRejectedList.push(onRejected)
+          this.onFulfilledList.push(() => {+              const value = onFulfilled(this.value)
+              resolve(value)
+            })
+          this.onRejectedList.push(() => {+              const reason = onRejected(this.reason)
+              // 留神这里是 resove
+              resolve(reason)
+            })
+        })
    }
  }

如何解决 返回值为 Promise 的场景?

  • 当以后 Promise 的返回值 依然是一个 Promise 时,以后 then 办法依然要将返回的 Promise 的值返回,即要 保障 then 中的回调函数拿到的后果不是一个 thenable 的数据
  class PbPromise{constructor(executor){
      this.state = PENDING
      this.value = undefined
      this.reason = null
      this.onFulfilledList = []
      this.onRejectedList = []

      // 用于将以后 Promise 状态转换为 FULLFILLED
      const resolve = value => {
        // 状态只能转变一次
        if(this.state !== PENDING) return 
        this.state = FULLFILLED

        this.value = value      
        // 状态发生变化 要 回调 then 存储的回调函数
        this.onFulfilledList.forEach(f => f())
      }

      // 用于将以后 Promise 状态转换为 REJECTED
      const reject = reason => {
        // 状态只能转变一次
        if(this.state !== PENDING) return 
        this.state = REJECTED

        this.reason = reason
        // 状态发生变化 要 回调 then 存储的回调函数
        this.onRejectedList.forEach(f => f())
        
      }

      // 此时内部通过 调用 resolve 或者 reject 就能够扭转 Promise 外部的状态
      executor(resolve, reject)
    }

    // 承受回调函数,并进行执行 / 存储
    then(onFulfilled, onRejected){return new PbPromise((resolve, reject) => {
        // 查看以后状态,非 PENDING 间接执行回调函数
        if(this.state === FULLFILLED){const value = onFulfilled(this.value)
+            // 解决返回值为 Promise 的场景
+            if(typeof value === 'object' && typeof value.then === 'function') {+              return value.then(resolve, reject)
+            }
          return resolve(value)
        }
        if(this.state === REJECTED){const reason = onRejected(this.reason)
+            // 解决返回值为 Promise 的场景
+            if(typeof reason === 'object' && typeof reason.then === 'function') {+              return reason.then(resolve, reject)
+            }
          return resolve(reason)
        }

        // PENDING 状态须要将回调函数存储起来,此时须要两个列表来存储回调函数
        // onFulfilledList onRejectedList
        // 这些回调函数应该在 resolve 办法 或者 reject 办法调用之后立刻调用
        this.onFulfilledList.push(() => {const value = onFulfilled(this.value)
+              // 解决返回值为 Promise 的场景
+              if(typeof value === 'object' && typeof value.then === 'function') {+                return value.then(resolve, reject)
+              }
           resolve(value)
          })
        this.onRejectedList.push(() => {const reason = onRejected(this.reason)
+              // 解决返回值为 Promise 的场景
+              if(typeof reason === 'object' && typeof reason.then === 'function') {+                return reason.then(resolve, reject)
+              }
            resolve(reason)
          })
      })
    }
  }

代码异样的 catch

  • 通过 try catch 将异样捕捉并抛出
    class PbPromise{constructor(executor){
        this.state = PENDING
        this.value = undefined
        this.reason = null
        this.onFulfilledList = []
        this.onRejectedList = []

        // 用于将以后 Promise 状态转换为 FULLFILLED
        const resolve = value => {
          // 状态只能转变一次
          if(this.state !== PENDING) return 
          this.state = FULLFILLED

          this.value = value      
          // 状态发生变化 要 回调 then 存储的回调函数
          this.onFulfilledList.forEach(f => f())
        }

        // 用于将以后 Promise 状态转换为 REJECTED
        const reject = reason => {
          // 状态只能转变一次
          if(this.state !== PENDING) return 
          this.state = REJECTED

          this.reason = reason
          // 状态发生变化 要 回调 then 存储的回调函数
          this.onRejectedList.forEach(f => f())
          
        }

        // 此时内部通过 调用 resolve 或者 reject 就能够扭转 Promise 外部的状态
        executor(resolve, reject)
      }

      // 承受回调函数,并进行执行 / 存储
      then(onFulfilled, onRejected){return new PbPromise((resolve, reject) => {
          // 查看以后状态,非 PENDING 间接执行回调函数
          if(this.state === FULLFILLED){
+            try {const value = onFulfilled(this.value)
              // 解决返回值为 Promise 的场景
              if(typeof value === 'object' && typeof value.then === 'function') {return value.then(resolve, reject)
              }
              return resolve(value)
+            }catch(e){+              return reject(e)
+            }
          }
          if(this.state === REJECTED){
+            try{const reason = onRejected(this.reason)
              // 解决返回值为 Promise 的场景
              if(typeof reason === 'object' && typeof reason.then === 'function') {return reason.then(resolve, reject)
              }
              return resolve(reason)
+            }catch(e){+              return reject(reason)
+            }
          }

          // PENDING 状态须要将回调函数存储起来,此时须要两个列表来存储回调函数
          // onFulfilledList onRejectedList
          // 这些回调函数应该在 resolve 办法 或者 reject 办法调用之后立刻调用
          this.onFulfilledList.push(() => {
+              try{const value = onFulfilled(this.value)
                // 解决返回值为 Promise 的场景
                if(typeof value === 'object' && typeof value.then === 'function') {return value.then(resolve, reject)
                }
                resolve(value)
+              }catch(e){+                reject(e)
+              }
            })
          this.onRejectedList.push(() => {
+              try{const reason = onRejected(this.reason)
                // 解决返回值为 Promise 的场景
                if(typeof reason === 'object' && typeof reason.then === 'function') {return reason.then(resolve, reject)
                }
                resolve(reason)
+             }catch(e){+               reject(e)
+             }
            })
        })
      }
    }

代码化简

  • 抽离 then 办法中调用回调函数的逻辑
  • 抽离 try catch
  class PbPromise{constructor(executor){
      this.state = PENDING
      this.value = undefined
      this.reason = null
      this.onFulfilledList = []
      this.onRejectedList = []

      // 用于将以后 Promise 状态转换为 FULLFILLED
      const resolve = value => {
        // 状态只能转变一次
        if(this.state !== PENDING) return 
        this.state = FULLFILLED

        this.value = value      
        // 状态发生变化 要 回调 then 存储的回调函数
        this.onFulfilledList.forEach(f => f())
      }

      // 用于将以后 Promise 状态转换为 REJECTED
      const reject = reason => {
        // 状态只能转变一次
        if(this.state !== PENDING) return 
        this.state = REJECTED

        this.reason = reason
        // 状态发生变化 要 回调 then 存储的回调函数
        this.onRejectedList.forEach(f => f())
        
      }
      // 此时内部通过 调用 resolve 或者 reject 就能够扭转 Promise 外部的状态
      executor(resolve, reject)
    }

    // 承受回调函数,并进行执行 / 存储
    then(onFulfilled, onRejected){return new PbPromise((resolve, reject) => {
        // 查看以后状态,非 PENDING 间接执行回调函数
        if(this.state === FULLFILLED){
-            try {-              const value = onFulfilled(this.value)
-              // 解决返回值为 Promise 的场景
-              if(typeof value === 'object' && typeof value.then === 'function') {-                return value.then(resolve, reject)
-              }
-              return resolve(value)
-            }catch(e){-              return reject(e)
-            }
+            return this.tryCatchFn(this.handleResolve(onFulfilled, resolve, reject), reject)()}
        if(this.state === REJECTED){
-            try{-              const reason = onRejected(this.reason)
-              // 解决返回值为 Promise 的场景
-              if(typeof reason === 'object' && typeof reason.then === 'function') {-                return reason.then(resolve, reject)
-              }
-              return resolve(reason)
-            }catch(e){-              return reject(reason)
-            }
+            return this.tryCatchFn(this.handleReject(onRejected, resolve, reject), reject)()}

        // PENDING 状态须要将回调函数存储起来,此时须要两个列表来存储回调函数
        // onFulfilledList onRejectedList
        // 这些回调函数应该在 resolve 办法 或者 reject 办法调用之后立刻调用
-          this.onFulfilledList.push(() => {
-              try{-                const value = onFulfilled(this.value)
-                // 解决返回值为 Promise 的场景
-                if(typeof value === 'object' && typeof value.then === 'function') {-                  return value.then(resolve, reject)
-                }
-                resolve(value)
-              }catch(e){-                reject(e)
-              }
-            })
-          this.onRejectedList.push(() => {
-              try{-                const reason = onRejected(this.reason)
-                // 解决返回值为 Promise 的场景
-                if(typeof reason === 'object' && typeof reason.then === 'function') {-                  return reason.then(resolve, reject)
-                }
-                resolve(reason)
-             }catch(e){-               reject(e)
-             }
-            })
+          this.onFulfilledList.push(this.tryCatchFn(this.handleResolve(onFulfilled, resolve, reject), reject))
+          this.onRejectedList.push(this.tryCatchFn(this.handleReject(onRejected, resolve, reject), reject))
      })
    }

+      handleResolve(onFulfilled, resolve, reject){+        return () => {+          const value = onFulfilled(this.value)
+          // 解决返回值为 Promise 的场景
+          if(typeof value === 'object' && typeof value.then === 'function') {+            return value.then(resolve, reject)
+          }
+          resolve(value)
+        }
+      }

+      handleReject(onRejected, resolve, reject){+        return () => {+          const reason = onRejected(this.reason)
+          // 解决返回值为 Promise 的场景
+          if(typeof reason === 'object' && typeof reason.then === 'function') {+            return reason.then(resolve, reject)
+          }
+          resolve(reason)
+        }
+      }

+      tryCatchFn(fn, catchFn){+        return () => {
+          try {+            fn()
+          }catch (e){+            catchFn(e)
+          }
+        }
+      }
  }

then 办法中的回调函数必须是异步执行的

  • then 办法中回调函数的异步执行,能够通过 setTimeout setImmediate,MutationObserver, process.nextTick 来进行 模仿,留神这里只是进行异步调用的模仿,并不是说原生的 promise 就是通过以上形式实现。因为波及到微工作与宏工作之间的执行程序,这里并不能齐全的模仿实现
  class PbPromise{constructor(executor){
      this.state = PENDING
      this.value = undefined
      this.reason = null
      this.onFulfilledList = []
      this.onRejectedList = []

      // 用于将以后 Promise 状态转换为 FULLFILLED
      const resolve = value => {
        // 状态只能转变一次
        if(this.state !== PENDING) return 
        this.state = FULLFILLED

        this.value = value      
        // 状态发生变化 要 回调 then 存储的回调函数
        this.onFulfilledList.forEach(f => f())
      }

      // 用于将以后 Promise 状态转换为 REJECTED
      const reject = reason => {
        // 状态只能转变一次
        if(this.state !== PENDING) return 
        this.state = REJECTED

        this.reason = reason
        // 状态发生变化 要 回调 then 存储的回调函数
        this.onRejectedList.forEach(f => f())
        
      }
      // 此时内部通过 调用 resolve 或者 reject 就能够扭转 Promise 外部的状态
      executor(resolve, reject)
    }

    // 承受回调函数,并进行执行 / 存储
    then(onFulfilled, onRejected){return new PbPromise((resolve, reject) => {
        // 查看以后状态,非 PENDING 间接执行回调函数
        if(this.state === FULLFILLED){-            return this.tryCatchFn(this.handleResolve(onFulfilled, resolve, reject), reject)()
+            // 通过 setTimeout 来模仿实现异步调用
+            setTimeout(this.tryCatchFn(this.handleResolve(onFulfilled, resolve, reject), reject))
        }
        if(this.state === REJECTED){-            return this.tryCatchFn(this.handleReject(onRejected, resolve, reject), reject)()
+            // 通过 setTimeout 来模仿实现异步调用
+            setTimeout(this.tryCatchFn(this.handleReject(onRejected, resolve, reject), reject))
        }

        // PENDING 状态须要将回调函数存储起来,此时须要两个列表来存储回调函数
        // onFulfilledList onRejectedList
        // 这些回调函数应该在 resolve 办法 或者 reject 办法调用之后立刻调用
        this.onFulfilledList.push(this.tryCatchFn(this.handleResolve(onFulfilled, resolve, reject), reject))
        this.onRejectedList.push(this.tryCatchFn(this.handleReject(onRejected, resolve, reject), reject))
      })
    }

    handleResolve(onFulfilled, resolve, reject){return () => {const value = onFulfilled(this.value)
        // 解决返回值为 Promise 的场景
        if(typeof value === 'object' && typeof value.then === 'function') {return value.then(resolve, reject)
        }
        resolve(value)
      }
    }

    handleReject(onRejected, resolve, reject){return () => {const reason = onRejected(this.reason)
        // 解决返回值为 Promise 的场景
        if(typeof reason === 'object' && typeof reason.then === 'function') {return reason.then(resolve, reject)
        }
        resolve(reason)
      }
    }

    tryCatchFn(fn, catchFn){return () => {
        try {fn()
        }catch (e){catchFn(e)
        }
      }
    }
  }

onRejected,onFulfilled 可选 以及 reject 穿透

  • onRejected,onFulfilled 两个回调函数是可选的,因而以后 promise 返回的数据 resolve 或者 reject 之后,value, reason 应该可能传递给接下来的 onFulfilled, onRejected,办法进行解决。
+ const NOOP = () => {}

class PbPromise{constructor(executor){
    this.state = PENDING
    this.value = undefined
    this.reason = null
    this.onFulfilledList = []
    this.onRejectedList = []

    // 用于将以后 Promise 状态转换为 FULLFILLED
    const resolve = value => {
      // 状态只能转变一次
      if(this.state !== PENDING) return 
      this.state = FULLFILLED

      this.value = value      
      // 状态发生变化 要 回调 then 存储的回调函数
      this.onFulfilledList.forEach(f => f())
    }

    // 用于将以后 Promise 状态转换为 REJECTED
    const reject = reason => {
      // 状态只能转变一次
      if(this.state !== PENDING) return 
      this.state = REJECTED

      this.reason = reason
      // 状态发生变化 要 回调 then 存储的回调函数
      this.onRejectedList.forEach(f => f())
      
    }
    // 此时内部通过 调用 resolve 或者 reject 就能够扭转 Promise 外部的状态
    executor(resolve, reject)
  }

  // 承受回调函数,并进行执行 / 存储
-  then(onFulfilled, onRejected){+  then(onFulfilled = NOOP, onRejected = NOOP){+    if(typeof onFulfilled !== 'function') onFulfilled = NOOP;
+    if(typeof onRejected !== 'function') onRejected = NOOP;
    return new PbPromise((resolve, reject) => {
      // 查看以后状态,非 PENDING 间接执行回调函数
      if(this.state === FULLFILLED){
        // 通过 setTimeout 来模仿实现异步调用
        setTimeout(this.tryCatchFn(this.handleResolve(onFulfilled, resolve, reject), reject))
      }
      if(this.state === REJECTED){
        // 通过 setTimeout 来模仿实现异步调用
        setTimeout(this.tryCatchFn(this.handleReject(onRejected, resolve, reject), reject))
      }

      // PENDING 状态须要将回调函数存储起来,此时须要两个列表来存储回调函数
      // onFulfilledList onRejectedList
      // 这些回调函数应该在 resolve 办法 或者 reject 办法调用之后立刻调用
      this.onFulfilledList.push(this.tryCatchFn(this.handleResolve(onFulfilled, resolve, reject), reject))
      this.onRejectedList.push(this.tryCatchFn(this.handleReject(onRejected, resolve, reject), reject))
    })
  }

  handleResolve(onFulfilled, resolve, reject){return () => {
+      // resolve 穿透
+      if(onFulfilled === NOOP) return resolve(this.value)
      const value = onFulfilled(this.value)
      // 解决返回值为 Promise 的场景
      if(typeof value === 'object' && typeof value.then === 'function') {return value.then(resolve, reject)
      }
      resolve(value)
    }
  }

  handleReject(onRejected, resolve, reject){return () => {
+      // reject 穿透
+      if(onRejected === NOOP) return reject(this.reason)
      const reason = onRejected(this.reason)
      // 解决返回值为 Promise 的场景
      if(typeof reason === 'object' && typeof reason.then === 'function') {return reason.then(resolve, reject)
      }
      resolve(reason)
    }
  }

  tryCatchFn(fn, catchFn){return () => {
      try {fn()
      }catch (e){catchFn(e)
      }
    }
  }
}

其余

  • 这里仅仅是对 Promise 的一种简略粗略的实现,
  • 值得注意的是 [1] 中有阐明 promise 在事件循环中的地位可能会依据实现有所不同

[1] Promise/A+ https://promisesaplus.com
[2] https://promisesaplus.com/#notes

退出移动版