手写Promise

220 阅读2分钟

关于Promise的定义,promise是什么,大家可自行翻阅阮一峰-《ECMAScript 6》

废话不多,直接上代码

Promise的基本用法

new MyPromise((resolve, reject) => {
    resolve(1)
}).then((v) => {
    console.log(v)
})

参考以上Promise的基本用法,我们基本确定我们代码的大体结构,

const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECT = 'reject'

function MyPromise(fn){
    let that = this
    that.state = PENDING     that.value = null
    that.resolvedCallbacks = []
    that.rejectCallbacks = []
}

MyPromise.prototype.then = function(onresolved, onreject) {
    
}

  • 首先,初始化三个状态,使用常量来保存着三个状态,便于后期的维护和管理;
  • 声明that保存this指向,在之后的代码中可能存在异步调用,以确保this指向的正确性;
  • 初始化状态state为pending;
  • 创建value属性,来保存resolve和reject传入的值;
  • 创建resolvedCallbacks 和rejectCallbacks用于保存在then方法中的回调函数,在状态变化调用,因为有可能在MyPromise执行完之后,状态还未改变;
  • 在MyPromise的原型对象上创建then方法;


接下来,我们继续完善resolve,reject方法,在MyPromise函数体中

function resolve(value) {
    if(that.state === PENDING) {
        that.state = RESOLVED
        that.value = value
        that.resolvedCallbacks.map(cb => cb(that.value))
    }
}

function reject(value) {
    if(that.state === PENDING) {
        that.state = REJECT
        that.value = value
        that.rejectCallbacks.map(cb => cb(that.value))
    }
}

  • resolve和reject都需要判断state是否为等待中,因为只有在state为等待中时,才能改变状态;
  • 改变状态为对应状态,将value赋给that.value
  • 遍历调用回调数组


执行fn,在MyPromise函数体中

try{
    fn(resolve, reject)
}catch(e) {
    reject(e)
}

  • 将resolve,reject作为fn的参数,传入fn;
  • 使用try{}catch(){}捕获执行fn时的错误;


最后,我们来实现较为复杂的then函数

MyPromise.prototype.then = function(onResolved, onReject) {
    let that = this
    onResolved = typeof onResolved === 'function' ? onResolved : v => v
    onReject = typeof onReject === 'function' ? onReject : r => {throw r}
    
    if(that.state === PENDING) {
        that.resolvedCallbacks.push(onResolved)
        that.rejectCallbacks.push(onReject)
    }

    if(that.state === RESOLVED) {
        onResolved(that.value)
    }

    if(that.state === REJECT) {
        onReject(that.value)
    }
}

  • 首先判断两个参数是否为函数,因为这两个参数为非必填参数
  • 之后根据每种状态,执行不同操作


以上就是简单版的Promise的思路和实现;

之后会继续更新符合promise/A+规范的promise,大家可以先了解下promise/A+规范


以下为本次实现的完整代码

const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECT = 'reject'
function MyPromise(fn) {  
    let that = this  
    that.state = PENDING  
    that.value = null  
    that.resolvedCallbacks = []  
    that.rejectCallbacks = [] 
     
    function resolve(value) {
        if(that.state === PENDING) {
          that.state = RESOLVED
          that.value = value
          that.resolvedCallbacks.map(cb => cb(value))
        }
    }  
    function reject(value) {
        if(that.state === PENDING) {
          that.state = REJECT
          that.value = value
          that.rejectCallbacks.map(cb => cb(value))
        }  
    }

    try {
        fn(resolve, reject)
    } catch(e) {
        reject(e)
    }
}

MyPromise.prototype.then = function(onResolved, onReject) {
    const that = this
    onResolved = typeof onResolved === 'function' ? onResolved : v => v
    onReject = typeof onReject === 'function' ? onReject : r => { throw r }

    if(that.state === PENDING) {
        that.resolvedCallbacks.push(onResolved)
        that.rejectCallbacks.push(onReject)
    }

    if(that.state === RESOLVED) {
        onResolved(that.value)  
    }

    if(that.state === REJECT) {
        onReject(that.value)  
    }
}