美文网首页
JavaScript之Promise实现

JavaScript之Promise实现

作者: 李牙刷儿 | 来源:发表于2017-12-18 20:28 被阅读204次

    ES2015提出了Promise,同时基于Promise的异步开发将开发者中回调地狱中解救出来。但在没有原生支持的环境下,需要借助Promise/A+之类的库来实现Promise,今天就来尝试自行实现Promise。

    1 基本实现

    首先来完成一个Promise类的基本框架:

    function Promise(fn) {
      var resolveCallback = null
      var rejectCallback = null
      
      this.then = function(onResolved, onRejected) {
          resolveCallback = onResolved
          rejectCallback = onRejected
      }
      
      this.resolve = function(value) {
          this.resolveCallback(value)
      }
      
      this.reject = function(reason) {
          this.rejectCallback(reason)
      }
      
      fn(this.resolve, this.reject)
    }
    

    以上便是Promise的基本实现。

    2 状态管理

    上述的代码存在一个问题,resolve方法会调用多次,所以接下来我们需要接入状态管理。

    Promise内部存在3个状态:

    • pending
    • resolved
    • rejected

    接下来在现有代码之上,加入状态管理:

    function MyPromise(fn) {
      let state = 'pending'
      var resolveCallback = null
      var rejectCallback = null
      var childResolve
      var childReject
      
      this.then = function(onResolved, onRejected) {
          resolveCallback = onResolved
          rejectCallback = onRejected
      }
      
      this.resolve = function(value) {
          if(state === 'pending') {
             this.resolveCallback(value)
             state = 'resolved' 
          } 
      }
      
      this.reject = function(reason) {
          if(state === 'pending') {
              this.rejectCallback(reason)
              state = 'rejected'
          }   
      }
      
      fn(this.resolve, this.reject)
    }
    

    3 链式调用

    上述Promise实现可以完成正常的异步调用,但是却无法实现链式回调,原因在于其then方法没有返回一个新的Promise对象,所以接下来还需要改造then方法,实现链式调用:

      this.then = function(onResolved, onRejected) {
          if(state === 'pending') {
            resolveCallback = onResolved
            rejectCallback = onRejected
          }
        
          return new MyPromise((resolve, reject) => {
            ......
          })
      }
    

    光返回一个promise对象还没用,接下来我们来写个demo测试下:

      var demo = new MyPromise((resolve, reject) => {
          setTimeout(() => {
              resolve('my first promise')
          }, 1000)
      })
    
      demo.then((msg) => {
          console.log(msg)
          return 'my second promise'
      }).then((msg) => {
          console.log(msg)
      })
    

    其输出为:

    my first promise
    

    事实上,第二个promise对象的resolve reject方法从未被调用过,因而其onResolved onRejected的回调ye就无从调用。所以还必须指定时机调用字promise对象的resolvereject

    所以首先需要在创建新promise对象时,记录其resolvereject方法:

    function MyPromise() {
        ......
        var childResolve
        var childReject
        
          this.then = function(onResolved, onRejected) {
          if(state === 'pending') {
            resolveCallback = onResolved
            rejectCallback = onRejected
          }
        
          return new MyPromise((resolve, reject) => {
            childResolve = resolve
            childReject = reject
          })
      }
    }
    

    接下来还需在resolvereject方法中调用子对象的resolvereject方法,整个Promise完整代码如下:

    function MyPromise(fn) {
        let state = 'pending'
        var resolveCallback = null
        var rejectCallback = null
        var childResolve = null
        var childReject = null
        
        this.then = function(onResolved, onRejected) {
            if(state === 'pending') {
                resolveCallback = onResolved
                rejectCallback = onRejected
            }
          
            return new MyPromise((resolve, reject) => {
                childResolve = resolve
                childReject = reject
            })
        }
        
        this.resolve = function(value) {
            if(state === 'pending') {
                if(resolveCallback) {
                    var ret = resolveCallback(value)
                    childResolve(ret)
                    state = 'resolved' 
                }
    
            } 
        }
        
        this.reject = function(reason) {
            if(state === 'pending') {
                if(rejectCallback) {
                    var ret = rejectCallback(reason)
                    childReject(ret)
                    state = 'rejected'
                }
            }   
        }
        
        fn(this.resolve, this.reject)
      }
    

    相关文章

      网友评论

          本文标题:JavaScript之Promise实现

          本文链接:https://www.haomeiwen.com/subject/elfvwxtx.html