三步完成A+规范Promise,平均一行代码一句注释(上)

1,060 阅读4分钟

前言

这篇文章系列是由我上培训班课程的一个笔记整理后完成。

带小白一步步完成一个A+规范Promise实现,由浅入深。

内容解析非常详细,尽量把每个点为什么这样写都注释清楚,某些地方甚至略显啰嗦了。

平均一行代码一句注释,拆分为三个版本1.0,2.0,3.0,层层递进,最终3.0版本将实现Pomise/A+规范。(1.0版本保证简单易懂)

至于本文为什么分为上中下三篇,是怕很多人和我一样看见太长的文章先收藏,再吃灰。

所以,绝不是懒:)。(其实就是)

myPromise 1.0 介绍

熟悉promise的读者可以直接看下一节源码

myPromise 1.0版本将完成一个能处理同步状态的promise(不考虑异步)。实现了promise的以下特性,很多日常使用的时候并没有注意到,却不知不觉在用了。

1.promise构造函数接收一个executor函数,且该函数立即执行(即同步执行)

2.executor函数接收两个promise内部提供的方法resolve方法reject方法用于供使用者调用,在合适的时候改变promise成合适的状态

let mypromise = new Promise((resolve,reject) => {
  //这个箭头函数就是executor
})

3.executor函数内部执行异常时会被捕获并执行reject

let mypromise = new Promise((resolve,reject) => {
  throw new Error('抛出异常')
  //相当于执行了reject,代码出现错误同理,会被捕获且将错误传给reject并执行。
})

4.具备三个状态(fulfilled成功,rejected失败,pending等待)和then方法(使用者用于传入onFulfilled函数onRejected函数)

let mypromise = new Promise((resolve,reject) => {
  resolve('成功')
})
mypromise.then((data) => { //onFulfilled函数
  console.log('then resolve---',data);
},(err) => { //onRejected函数
  console.log('then reject---',err);
})
//注意:then中的使用者传入的onFulfilled函数和使用者executor中使用的resolve都是成功时要调用的方法,可以认为resolve触发onFulfilled。

//reject和onRejected同上

5.promise默认处于pending状态,且只有promise处于pending状态时,内部的executor才能成功调用resolvereject并改变状态。

let mypromise = new Promise((resolve,reject) => {
  resolve('成功')//resolve内部会改变状态由pending变resolve
  resolve('成功2')//这三行执行已经没有反应
  reject('失败')
  throw new Error('抛出异常')
})

myPromise 1.0 源码

知道特性之后就是开始实现了,不得不感叹大佬们的智慧。

不多说,开始上代码,话都在注释里。

// myPromise 1.0
const RESOLVED = 'RESOLVED'
const REJECTED = 'REJECTED'
const PENDING = 'PENDING'
console.log('my promise working');
class Promise {
  constructor(executor) {//new Promise时,立即调用构造函数constructor,接收用户传入的executor。
    this.status = PENDING;//默认等待态
    this.value = undefined;//用于成功时数据存储,可能是js值,undefined,promise三者之一
    this.reason = undefined;//用于失败原因储存

    let resolve = (value) => {//这两个函数不绑定到this上是因为,这两个函数不属于实例,由使用者传入
      if(this.status === PENDING) {//只有等待态才能改变状态并执行resolve函数,非等待态调用直接return
        this.status = RESOLVED//用户调用resolve时第一步,状态置为'resolve'
        this.value = value//第二步,保存成功消息
      } 
    }

    let reject = (reason) => {//同上
      if(this.status === PENDING) {//状态已经是resove或reject的时候即使调用也不执行
        this.status = REJECTED
        this.reason = reason
      }
    }

    
    try {//在executor外包裹trycatch是为了捕获运行时的错误,以及throw new Error()这种非用户主动调用reject时的情况。
      executor(resolve,reject);//执行器就是executor用户传入的函数,该函数立即执行
      //并传入两个函数给执行器使用。
      //并约定,用户认为成功或者说想调用'成功'方法或者是想将状态置为成功时使用resolve,并传入成功消息
      //反之调用reject,并传入失败原因
    } catch (error) {//假设trycatch捕获到错误,自动调用reject。
      reject(error)//也就是说,用户主动调用reject和promise内executor运行出错都会调用reject。
    }
    
  }


  //上面是promise调用时初始化执行的构造器,下面是promise这个类自带的方法
  then(onFulfilled,onRejected) { //使用者调用promise的then方法,传入成功时调用的函数,失败时调用的函数
    if(this.status === RESOLVED) {//然后then执行,根据promise的状态决定调用的函数
      onFulfilled(this.value);
    }
    if(this.status === REJECTED) {
      onRejected(this.reason)
    }
  }
}

module.exports = Promise

//也就是说,用户调用promise,promise立即执行,并改变promise的状态,当用户调用then的时候
//传入两个状态对应的要执行的方法。promise根据当前状态的不同,选择执行resolve或reject

马上试试

let Promise = require('./promise') //引入自己的promise实验一下

let mypromise = new Promise((resolve,reject) => {
  resolve('成功')//改变状态由pending变resolve
  throw new Error('抛出异常')//后两行执行已经没有反应
  reject('失败')
})
mypromise.then((data) => {
  console.log('then resolve---',data);
},(err) => {
  console.log('then reject---',err);
})

最后输出:my promise working then resolve--- 成功

总结

如果能帮到大家就是对我最大的鼓励,1.5和2.0代码注释版已经基本完成,写好后会排markdown版发出。

下期,1.5版本作为过渡,2.0版本将解决异步、链式调用的问题。

myPromise1.0其实很简单的东西,但是也不排除有没发现的错误,大家轻喷,感谢阅读,感谢指错。