JavaScript之Promise实现

98 阅读3分钟
原文链接: click.aliyun.com

JavaScript之Promise实现

李牙刷儿 2017-12-18 20:42:48 浏览42 评论0 发表于: 阿里云ApsaraMobile(移动云)

前端与交互设计 javascript demo

摘要: 自己动手写Promise

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)
  }
本文为云栖社区原创内容,未经允许不得转载,如需转载请发送邮件至yqeditor@list.alibaba-inc.com;如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:yqgroup@service.aliyun.com 进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。

用云栖社区APP,舒服~

【云栖快讯】中办国办印发《推进互联网协议第六版(IPv6)规模部署行动计划》加快推进基于 IPv6 的下一代互联网规模部署,计划指出2025年末中国 IPv6 规模要达到世界第一,阿里云也第一时间宣布了将全面提供IPv6服务,那么在全面部署 IPV6 前,你需要了解都在这儿  详情请点击 评论文章 (0) (0) (0)

相关文章

网友评论