手写promise跑promiseA+规范

794 阅读4分钟

问题

我们带着问题去看源码promsie

  • promise 是什么,主要用来解决什么
  • promise 源码是如何进行解决的?
  • promise 有哪些实例方法和静态方法
  • promise 为什么可以进行链式调用
  • 怎样实现promise状态的不可逆

promise是什么?

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大,就是用同步的书写代码方式来替代回调地狱式的写法

promise 的状态

  • pending
  • fulfilled
  • rejected

promise的状态是不可逆的,只能从一种状态改变成另一种状态 ,一旦状态改变,就不会再变,Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。 因此可以相爱下面代码做了判断 在执行resolve的时候把状态改了,rejected的时候状态也变了

promise 的原型上的方法

promise 的原型上的方法也称为实例方法

  • then
  • catch
  • finally

promise 的静态方法

promise 静态方法就是构造函数上的方法

  • all
  • race
  • resolve
  • reject

promise源码

// 这个函数的作用主要就是判断x 是不是普通的值还是promsie
// 然后返回对应的成功状态或者失败状态进行传递值
function resolvePromise(promsie2, x, resolve, reject) {
    // 判断promise 是否等于自身
    // 如下面这种情况,就会出现等于自身的情况
    // let p = new Promise1((resove,reject)=>{
    //     resove()
    // })
    // let p2 = p.then((value)=>{
    //     console.log('成功',value)
    //     return p2
    // },(value)=>{
    //     console.log('失败',value)
    //     return 'hhhh'
    // })
    // p2.then(()=>{
    //     console.log('哈哈哈')
    // },(err)=>{
    //     console.log('www',err)
    // })
    
    if (promsie2 === x) {
        return reject(new TypeError(' Chaining cycle detected for promise #<Promise>'))
    }
    let called;  // 为了防止掉了成功 又调用失败
    // 然后就是判断x的类型  是否是常量 还是promise
    // 如何判断promise 是不是一个promise 看他有没有then方法 
    if (typeof x === 'function' || (typeof x === 'object' && x != null)) {
        try {
            let then = x.then  // then方法可能会出错
            if (typeof then === 'function') {
                then.call(x, y => { // 如果promise是成功的就把结果向下传,如果失败的就让下一个也失败
                    if (called) return
                    called = true
                    resolvePromise(promsie2, y, resolve, reject) // 递归 为了防止then一层层为promise
                    // resolve(y)
                }, r => {
                    if (called) return
                    called = true
                    reject(r)
                })  // 不要使用x.then 否则会再次取值s
            } else {
                resolve(x)
            }
        } catch (e) {
            if (called) return
            called = true
            reject(e)
        }
    } else {
        resolve(x)
    }



}
class Promise {
    constructor(extruct) {
        this.state = 'pending'
        this.value = undefined; //成功的值
        this.reason = undefined //失败的原用

        this.onResovleCallbacks = []
        this.onRejectedCallbacks = []
        let resolve = (value) => {
            // 为了防止这种情况发生
            // let p = new Promise((resove,reject)=>{
            //     resove(new Promise((resove,reject)=>{
            //         resove(100)
            //     }))
            // })
            if (value instanceof Promise) {
                // debugger
                return value.then(resolve, reject)
            }

            if (this.state === 'pending') {
                // debugger
                this.state = 'resolve'
                this.value = value
                this.onResovleCallbacks.forEach(fu => fu())
            }
        }
        let reject = (value) => {
            if (this.state === 'pending') {
                this.state = 'reject'
                this.reason = value
                this.onRejectedCallbacks.forEach(fu => fu())
            }
        }
        // try 方法  可能会在调用Promise 的时候直接出催
        try {
            extruct(resolve, reject)
        } catch (e) {
            reject(e)
        }

    }
    catch(errCallbak){ // 用来捕获错误的 .then(null,err=>err)
        return this.then(null,errCallbak)
    }
    then(onFulfilled, onRejected) {
        // debugger
        // 为了防止值的穿透事件  
        // 例如这种情况
        // let p = new Promise((resove,reject)=>{
        //     reject()
        // })
        // p.then(()=>{}).then(()=>{},(ee)=>{
        //     console.log(111)
        // })
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : data => data
        onRejected = typeof onRejected === 'function' ? onRejected : (err) => { throw err }
        let promsie2
        // 在promise中实现链式调用 靠的不是返回this 
        // 因为 promise 的状态是不可逆的 
        // 所以是返回了一个新的 promise
        promsie2 = new Promise((resolve, reject) => {
            if (this.state === 'resolve') {
                
                // setTimeout 的目的是为了获取 promsie2
                // 因为在刚开始的时候 promsie2 是不存在的
                setTimeout(() => {
                    // debugger
                    // x 为常量 x 为promise
                    // resolve(x)
                    try {
                        let x = onFulfilled(this.value)
                        // 这个函数主要目的是为了区分 x 是常量还是promise
                        resolvePromise(promsie2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }

                })
            }
            // debugger
            if (this.state === 'reject') {
                setTimeout(() => {
                    try {
                        let x = onRejected(this.reason)
                        resolvePromise(promsie2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }

                })
            }
            if (this.state === 'pending') {
                this.onResovleCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onFulfilled(this.value)
                            resolvePromise(promsie2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    })

                })
                this.onRejectedCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onRejected(this.reason)
                            resolvePromise(promsie2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    })
                })
            }
        })
        return promsie2
    }
    finally(callback){
        return this.then((data)=>{
            return new Promise((resolve,reject)=>{
                resolve(callback)
            }).then(()=>data)
        },err=>{
            return new Promise((resolve,reject)=>{
                resolve(callback)
            }).then(()=>{throw err})
        })
    }
}
// 其实就是返回了一个成功的promsie 
Promise.resolve = function(value){
    return new Promise((resolve,reject)=>{
        resolve(value)
    })
}

// 这是tj大神写的co库判断是否是isPromise的代码就是判断有没有then方法
// 如果有的话就是promsie
// function isPromise(obj) {
  // return 'function' == typeof obj.then;
// }

// 判断是否是promise
function isPromise(value){
    if(typeof value ==='function'|| (typeof value ==='object'&& typeof value !=null)){
        if(typeof value.then ==='function'){
            return true
        }
    }else{
        return false
    }
}
// Promise.all 接收的是一个数组作为参数
// 能够进行链式调用.then方法 因此内部是返回了一个promise
Promise.all = function(values){
    return new Promise((resolve,reject)=>{
        let arr = []
        let i=0;
        let processDate = (index,val)=>{
            arr[index]  = val
            i++
            if(i===values.length){
                resolve(arr)
            }
            // 这里用 i++ 
            // 是为了防止 a[1] 
            // 有值了 而a[0] 还没有值 就会出现a[0]没有收到值而reolve()
        }
        // values 有可能会这样[promise,promise,1,2],
        // 所以要判断是否是promsie
        for(let i=0;i<values.length;i++){
            let cuurent = values[i] 
            if(isPromise(cuurent)){
                cuurent.then((val)=>{
                    processDate(i,val)
                },(err)=>{
                    reject(err)
                })
            }else{
                processDate(i,cuurent)
            }
           
        }
    })
    
}

进行promise 测试

Promise.defer = Promise.deferred = function () {
    let dfd = {}
     dfd.promise = new Promise((resolve, reject) => {
         dfd.resolve = resolve;
         dfd.reject = reject;
     });
     return dfd;
 }
 module.exports = Promise
  • 可以全局安装 promises-aplus-tests
npm install promises-aplus-tests -g
  • 进行测试
promises-aplus-tests ./promise.js