简单实现 ES6 Promise

最近在使用ES6,所以手动实现了一个简单的ES6 Promise对象来玩玩(如果有错误的地方,希望大家能够不吝赐教)

一个promise对象接收的是一个callback
这个callback接收两个参数(resolve,reject)
当我们在callback内执行resolvereject的时候,就会调用Promise内定义的 resolvereject函数
然后,resolvereject函数会改变Promise的状态
所以它应该是像下面这样的

function MyPromise(callback) {
  // 保存this值
  var self = this
  // 记录状态null为pending,true为resolved,false为reject
  var state = null
  // 记录resolve的参数
  var param = null

  // 执行传入的callback并改变promise对象状态
  callback(resolve, reject)
  // resolve方法
  function resolve(data) {
    // 改变状态
    state = true
    param = data
  }

  // reject方法
  function reject(err) {
    state = false
    param = err
  }
}

但没有then方法的Promise对象是不完整的(完全没有用)
所以我们需要一个then方法,要记住then方法返回的也是一个promise对象
then方法接收两个可选的参数(onFulfilled, onRejected)(我们可以先忽略可选两个字)
then方法传进来的参数必须是函数,如果不是就要忽略(PromiseA+规范)(我们可以也先忽略这句话)

  this.then = function (onFulfilled, onRejected) {
    // 返回一个新的promise对象
    return new self.constructor(function (resolve, reject) {
      // then
    })
  }

接下来就是then方法的具体实现了
then方法中onFulfilled, onRejected的返回值会作为新promise的执行结果

onFulfilled, onRejected这两个函数要在promise的状态变为pending或resolved的时候才能分别执行
所以如果promise方法状态为resolvedrejected的话,我们就可以直接在then方法中执行resolve(onFulfilled(param))reject(onRejected(param))

  this.then = function (onFulfilled, onRejected) {
    // 返回一个新的promise对象
    return new self.constructor(function (resolve, reject) {
       if (state === true) {
        // param是promise对象完成后的结果
        resolve(onFulfilled(param))
      } else if (state === false) {
        reject(onRejected(param))
      } else {
        // 没有执行完毕,怎么办
      }
    })
  }

但如果promise的状态为pending
由于原始promise的状态我们是无法动态获取的,因此我们就需要在他执行状态改变的时候同时执行onFulfilledonRejected方法
我们可以把这个方法放在原始promise对象的resolvereject方法中执行
因此我们要在promise的对象定义中添加四个参数,分别记录onFulfilledonRejected,以及then方法返回的新promise对象的resolvereject
然后如果执行then方法的时候promise对象的状态为pending的话,就将上述四个参数记录起来

// then方法返回的promise对象的resolve和reject
var nextResolve = null
var nextReject = null
// 记录then方法的参数,onFulfilled和onRejected
var asynconFulfilled = null
var asynconRejected = null

//then方法
this.then = function (onFulfilled, onRejected) {
    // 返回一个新的promise对象
    return new self.constructor(function (resolve, reject) {
      if (state === true) {
        // param是promise对象完成后的结果
        resolve(onFulfilled(param))
      } else if (state === false) {
        reject(onRejected(param))
      } else {
        nextResolve = resolve
        nextReject = reject
        asynconFulfilled = onFulfilled
        asynconRejected = onRejected
      }
    })
  }

接下来就是原始promise中的resolvereject的重新实现

 // resolve方法
  function resolve(data) {
    // 改变状态
    state = true
    param = data
    nextResolve(asynconFulfilled(param))
  }

  // reject方法
  function reject(err) {
    state = false
    param = err
    nextReject(asynconRejected(param))
  }

很简单不是吗
我们继续
上述实现我们一直没有考虑一个很重要的情况,如果then方法返回的还是一个promise对象,那么如果我们后边还有then方法的话就要等待前一个then方法中的promise对象的状态从pending变为完成
这要怎么做呢
什么时候可以认为then方法返回的promise对象执行完毕了呢,这里我们就要用到then方法(@_@,边写边用...),
resolve方法为例

var self = this
// resolve方法
function resolve(data) {
  // 记录onFulfilled的执行结果
  let parmise
  // 改变状态
  state = true
  param = data
  // 执行记录的onFulfilled
  parmise = asynconFulfilled(param)
  if(parmise === undefined){
    // 如果parmise为undefined,就不能解析parmise.constructor
  } else if (parmise.constructor === self.constructor) {
    // 等待传递进来的promise对象执行完毕,然后根据传递进来的promise对象的状态执行resolve或reject
    // 注意,这个param是形参,在then方法的promise中执行
    promise.then(function (param) {
      resolve(param)
    }, function (param) {
      reject(param)
    })
  } else {
    // 这个是前边的then返回的不是promise对象的情况
    resolve(promise)
  }
}

前面我们忽略了两点 (then方法接收两个可选的参数(onFulfilled, onRejected)) 和 (then方法传进来的参数必须是函数,如果不是就要忽略)

var self = this
// resolve方法
function resolve(data) {
  // 记录onFulfilled的执行结果
  var parmise
  // 改变状态
  state = true
  param = data
  // 执行记录的onFulfilled
  // begin--------------
  if (typeof onFulfilled === 'function') {
    promise = onFulfilled(param)
    if (promise === undefined) {
      // 待补充
    } else if (promise.constructor === self.constructor) {
      // 注意,这个param是形参,在then方法的promise中执行
      promise.then(function (param) {
        resolve(param)
      }, function (param) {
        reject(param)
      })
    } else {
      reject(promise)
    }
  } else {
    // 如果onFulfilled不是function,忽略,直接resolve或reject
    resolve(param)
  }
  // ---------------end
}

上面begin到end之间的代码还要在then方法调用,所以我们可以把这段代码抽象为一个函数
resolvereject的原理相同,只要注意如果不是function 的话需要执行reject


onFulfilledonRejected只有在[执行环境]堆栈仅包含平台代码时才可被调用
所以将上述begin-end之间的代码放到seTimeout中执行(浏览器环境)

function resolve(data) {
  // 记录onFulfilled的执行结果
  var parmise
  // 改变状态
  state = true
  param = data
  // 执行记录的onFulfilled
  window.setTimeout(function () {
    // begin--------------
    // 上述代码
    // ---------------end
  }, 0)
}

下面是完整代码

// 简单实现ES6 Promise
function MyPromise(callback) {
  // 保存this值
  var self = this
  // 记录状态null为pending,true为resolved,false为reject
  var state = null
  // 记录resolve的参数
  var param = null
  // then方法返回的promise对象的resolve和reject
  var nextResolve = null
  var nextReject = null
  // 记录then方法的参数,onFulfilled和onRejected
  var asynconFulfilled = null
  var asynconRejected = null

  // 执行并改变promise对象状态
  callback(resolve, reject)
  // then方法
  this.then = function (onFulfilled, onRejected) {
    // 返回一个新的promise对象
    return new self.constructor(function (resolve, reject) {
      // 判断异步代码是否执行完毕(是否resolve或reject)
      // 若执行完毕就在then方法中立即执行,否则将四个参数记录下来,等待state就绪后再执行doAsyn*函数
      if (state === true) {
        doAsynconFulfilled(onFulfilled, resolve, reject)
      } else if (state === false) {
        doAsynconRejected(onRejected, resolve, reject)
      } else {
        nextResolve = resolve
        nextReject = reject
        asynconFulfilled = onFulfilled
        asynconRejected = onRejected
      }
    })
  }
  // resolve方法
  function resolve(data) {
    // 改变状态
    state = true
    param = data
    if(nextResolve){
        doAsynconFulfilled(asynconFulfilled, nextResolve, nextReject)
    }
  }

  // reject方法
  function reject(err) {
    state = false
    param = err
    if(nextReject){
        doAsynconRejected(asynconRejected, nextResolve, nextReject)
    }
  }

  // 核心方法(我觉得是)

  function doAsynconFulfilled(onFulfilled, resolve, reject) {
      window.setTimeout(function () {
        // 判断onFulfilled是否为function,不是则忽略
        if (typeof onFulfilled === 'function') {
          // 执行onFulfilled方法获取返回值promise()
          let promise = onFulfilled(param)
          // 如果promise为undefined 执行 if
          // 如果promise为MyPromise对象 执行 else if
          // 如果promise为非MyPromise对象 执行 else
          if (promise === undefined) {
            resolve(param)
            // 待补充
          } else if (promise.constructor === self.constructor) {
            // 等待传递进来的promise对象执行完毕,然后根据传递进来的promise对象的状态执行resolve或reject
            promise.then(function (param) {
              resolve(param)
            }, function (param) {
              reject(param)
            })
          } else {
            // 执行then方法返回的对象的resolve
            resolve(promise)
          }
        } else {
          // 传递参数
          resolve(param)
        }
      }, 0)
    
  }

  function doAsynconRejected(onRejected, resolve, reject) {
    window.setTimeout(function () {
        if (typeof onRejected === 'function') {
          let promise = onRejected(param)
          if (promise === undefined) {
            reject(param)
            // 待补充
          } else if (promise.constructor === self.constructor) {
            promise.then(function (param) {
              resolve(param)
            }, function (param) {
              reject(param)
            })
          } else {
            reject(promise)
          }
        } else {
          // 传递错误信息
          reject(param)
        }
    }, 0)
  }
}
// 测试使用
var b = function (message) {
    return new MyPromise(function (resolve, reject) {
        document.body.onclick = function () {
            resolve('click:' + message)
        }
    })
}
var a = new MyPromise(function (resolve, reject) {
  resolve(123)
}).then(function (message) {
    return b(message)
}).then().then(function (message) {
    console.log('final:' + message)
},function (err) {
    console.log('final:' + err)
})
console.log('window')

完毕!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容

  • 本文适用的读者 本文写给有一定Promise使用经验的人,如果你还没有使用过Promise,这篇文章可能不适合你,...
    HZ充电大喵阅读 7,296评论 6 19
  • Promiese 简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果,语法上说,Pr...
    雨飞飞雨阅读 3,348评论 0 19
  • Promise的含义:   Promise是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和...
    呼呼哥阅读 2,164评论 0 16
  • 00、前言Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区...
    夜幕小草阅读 2,127评论 0 12
  • 特点 Promise能将回调分离出来,在异步操作执行之后,用链式方法执行回调,虽然es5用封装函数也能实现,但是如...
    一二三kkxx阅读 616评论 0 1