手撕Promise/A+规范及其周边函数的源码实现

1 篇文章 0 订阅
1 篇文章 0 订阅

‘回调地狱’是每个前端工程师的噩梦,promise/A+的出现让我们如梦初醒,原来异步编程还可以这样实现,promise让每一位前端工程师爱不释手。它规范化了前端异步编程,因此也成为了前端面试者躲不开的话题。今天我就把promise的源码实现分享给大家,供学习、参考。

Promise

console.log('-------------------promise源码解析----------------------')
/**
 * 1. Promise 是一个类   exectuor 是一个立即执行函数
 * 2. 有三个状态 默认是【PENDING】 FULFILED (成功态)、REJECTED(失败态),状态一经改变不能再修改
 * 3. resolve和reject的结果传入到then中的回调函数中
 * 4. 发布订阅模式实现异步执行
 * 5. 如果promise返回一个普通值(不论是 resolve 还是reject中返回的)都传递到下一个then的成功中
 * 6. 如果返回一个错误 一定走到下一次的失败
 * 7. 如果返回的是一个promise 会采用promise的状态决定下一次的成功还是失败,如果离自己最近的then没有错误处理,会向下找。
 * 8. 每次执行promise.then 都会返回一个'全新的promise'
 */
// 中间态 未决态
const PENDING = 'PENDING'
// 成功态
const FULFILED = 'FULFILED'
// 失败态
const REJECTED = 'REJECTED'
const resolvePromise = (promise2, x, resolve, reject) => {
    // 循环引用 抛出异常
    if (promise2 === x) {
        return reject(new TypeError('TypeError: Chaining cycle detected for promise #<Promise>'))
    }
    // 防止第三方库状态会来回改变,调用多次
    let called;
    // 这里要进行严格的判断,因为这里还有兼容别人写的第三方的库实现的promise
    // 1. 先判断是否是一个promise
    if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
        // 2.还要有then方法
        /* 
            Object.defineProperty(x,'then',{
                get(){
                    throw new Error()
                }
            })
         */
        try {
            let then = x.then
            if (typeof then === 'function') {
                // 走到这里就认为是prommise
                // 不要写出x.then(),容易报错
                then.call(x, y => {
                    // 成功
                    if (called) return;
                    called = true;
                    resolvePromise(promise2, y, resolve, reject)
                }, e => {
                    // 失败
                    if (called) return;
                    called = true;
                    reject(e)
                })

            } else {
                // 可能是对象
                resolve(x)
            }
        } catch (error) {
            if (called) return;
            called = true;
            reject(error)
        }

    } else {
        resolve(x)
    }
}
class MyPromise {
    constructor(executor) {
        this.status = PENDING;
        this.value = null;
        this.reason = null;
        // 发布订阅模式
        this.onFulfiledcallback = [];
        this.onRejectedcallbalck = [];
        let resolve = (value) => {
            if (this.status === PENDING) {
                // 一旦成功,状态不能再改变
                this.status = FULFILED
                this.value = value
                this.onFulfiledcallback.forEach(fn => fn())
            }
        }
        let reject = (reason) => {
            if (this.status === PENDING) {
                // 一旦失败,状态不再改变
                this.status = REJECTED;
                this.reason = reason;
                this.onRejectedcallbalck.forEach(fn => fn())
            }
        }
        try {
            executor(resolve, reject)
        } catch (error) {
            // 如果异常,立即结束
            console.log('error', 'inner')
            reject(error)
        }

    }
    then(onFulfailed, onRejected) {
        onFulfailed = typeof onFulfailed === 'function' ? onFulfailed : v => v;
        onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
        // then的链式调用的处理规范
        const promise2 = new MyPromise((resolve, reject) => {
            if (this.status === FULFILED) {

                // 返回的x如果是一个普通值没有问题
                // 1. 如果返回的是一个promise 怎么办???
                // 2. 如果返回一个错误怎么办???/ ====> 会被executor的异常蒱货
                // 3.此时的promise2还没有创建完毕,会报错
                // 4.使用事件循环机制的宏任务来解决
                // let x = onFulfailed(this.value)
                // console.log('x', x)
                // resolvePromise(promise2, x, resolve, reject)
                setTimeout(() => {
                    // 5. 使用setTimeout之后,抛出的异常外面的executor的trycatch无法再蒱货到
                    // 6. 需要在这里再次trycatch
                    try {
                        let x = onFulfailed(this.value)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }

                }, 0)
            }
            if (this.status === REJECTED) {
                // let x = onRejected(this.reason)
                // console.log('x', x)
                // 返回的x如果是一个普通值没有问题
                // 1. 如果返回的是一个promise 怎么办???
                // 2. 如果返回一个错误怎么办???/
                // resolvePromise(promise2, x, resolve, reject)
                setTimeout(() => {
                    try {
                        let x = onRejected(this.reason)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }

                }, 0);
            }
            if (this.status === PENDING) {
                // 已下方式是可以的,有可能我们还会处理其他逻辑,
                // 所以我们会使用AOP的思想来进行编程(面向切片编程)
                // this.onFulfiledcallback.push(onFulfailed)
                // this.onRejectedcallbalck.push(onRejected)
                this.onFulfiledcallback.push(() => {
                    // todo other
                    // let x = onFulfailed(this.value)
                    // 返回的x如果是一个普通值没有问题
                    // 1. 如果返回的是一个promise 怎么办???
                    // 2. 如果返回一个错误怎么办???/
                    // resolvePromise(promise2, x, resolve, reject)
                    setTimeout(() => {
                        try {
                            let x = onFulfailed(this.value)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                })
                this.onRejectedcallbalck.push(() => {
                    // todo other
                    // let x = onRejected(this.reason)
                    // 返回的x如果是一个普通值没有问题
                    // 1. 如果返回的是一个promise 怎么办???
                    // 2. 如果返回一个错误怎么办???/
                    // resolvePromise(promise2, x, resolve, reject)
                    setTimeout(() => {
                        try {
                            let x = onRejected(this.reason)
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0);
                })
            }
        })

        return promise2
    }
    catch(errCallback) {
        // 实质是没有成功参数的then方法
        return this.then(null, errCallback)
    }
}
// Promise/A+ 规范 测试
MyPromise.deferred = function () {
    const dfd = {};
    dfd.promise = new MyPromise((resolve, reject) => {
        dfd.resolve = resolve;
        dfd.reject = reject;
    })
    return dfd;
}
// npm install promises-aplus-tests -g
// promises-aplus-tests 16.手写promise.js
module.exports = MyPromise

Promise.all(面试的机率 *****)

/* Promise.all 1.全部完成才叫完成 2.返回的还是一个promise */
/* 
    Promise.all源码解析
 */
Promise.all = function (promises) {
    return new Promise((resolve, reject) => {
        const arr = []
        // 解决异步并发的问题
        let i = 0;
        let processData = (index, data) => {
            arr[index] = data
            if (++i === promises.length) {
                resolve(arr)
            }
        }
        for (let i = 0; i < promises.length; i++) {
            let currentPromise = promises[i]
            if (isPromise(currentPromise)) {
                currentPromise.then(data => {
                    processData(i, data)
                }, reject)
            } else {
                processData(i, currentPromise)
            }
        }
    })

}

/**
 * 判断是否promise的方法
 * @param {*} promise 
 */
const isPromise = promise => {
    if ((typeof promise === 'object' && promise !== 'null') || typeof promise === 'function') {
        return typeof promise.then === 'function'
    } else {
        return false
    }
}

Promise.race

/** Promise.race源码解析
 * 1. 竞争机制
 * 2.返回一个promise
*/
Promise.race = function (promises) {
    return new Promise((resolve, reject) => {
        for(let i = 0, len = promises.length; i < len; i++) {
            let currentPromise = promises[i];
            if(isPromise(currentPromise)){
                currentPromise.then(resolve,reject)
            }else{
                resolve(currentPromise)
            }
        }
    })

}
/* 
    1. 是对象或者函数
    2. 具有then方法
 */
const isPromise = (promise) =>{
    if((typeof promise === 'object' && promise !== null) || typeof promise === 'function'){
        return typeof promise.then === 'function'
    }else{
        return false
    }
}

Promise.resolve

/**
 *  静态方法Promise.resolve源码解析
 * 1.返回一个Promise
 * 2.具有等待效果
 */

Promise.resolve = function (data) {
    return new Promise((resolve, reject) => {
        resolve(data)
    })
}

Promise.reject

/**
 *  静态方法Promise.reject源码解析
 * 1.返回一个Promise
 * 2.不具有等待效果
 */

Promise.reject = function (reason) {
    return new Promise((resolve, reject) => {
        reject(reason)
    })
}

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值