今天教你手写 Promise

Posted 小北哥哥和北妈

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了今天教你手写 Promise相关的知识,希望对你有一定的参考价值。

大家好,我是梦起

今天我们来聊聊常见的前端手写功能之Promise

首先我们来聊聊要实现的功能:

1、Promise就是一个类,在执行类的时候,需要传递一个执行器(函数)进去,执行器会立刻执行

2、Promise有三种状态,分别为 等待 pending 成功 fulfilled 失败 rejected

pending => fulfilled || pending => rejected

状态一旦确定就不能改变

3、resolve和reject是用来更改状态的

resolve : fulfilled

reject : rejected

4、then方法内部做的事情就是判断状态 如果状态是成功 调用成功的返回函数 如果状态是失败 调用失败的回调函数 then方法是被定义在原型对象中的

5、then成功回调有一个参数,表示成功之后的值,then失败回调有一个参数,表示失败的原因

6、同一个promise对象下面的then方法是可以被调用多次的,then方法是可以链式调用的,后面的then方法回调函数拿到的值是上一个then方法的回调函数的返回值

确定功能后呢,接下来我们就要开始写代码了

const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";


class MyPromise
    constructor (executor) 
        try  // 尝试调用执行器
            executor(this.resolve,this.reject)
         catch(e)  // 调用失败
            this.reject(e)
        
        
    
    // Promise 状态初始化为等待
    status = PENDING;
    // 成功之后的值
    value = undefined;
    // 失败的原因
    reason = undefined;
    // 成功的回调函数存放的数组
    successCallback = [];
    // 失败的回调函数存放额数组
    failCallback = [];


    resolve = value => 
        // 如果状态不是等待 阻止程序向下执行
        if(this.status !== PENDING) return
        // 更改状态为成功
        this.status = FULFILLED
        // 保存成功之后的值
        this.value = value
        // 成功回调存在 调用成功回调方法
        // this.successCallback && this.successCallback(this.value)
        // 因为then是可以多次调用的
        // this.successCallback.shift(),截取数组中的第一个元素并返回,会改变原数组
        while(this.successCallback.length) this.successCallback.shift()(this.value)
    
    reject = reason => 
        if(this.status !== PENDING) return
        // 更改状态为失败
        this.status = REJECTED
        // 保存失败的值
        this.reason = reason
        // 成功回调存在 调用成功回调方法
        // this.failCallback && this.failCallback(this.value)
        while(this.failCallback.length) this.failCallback.shift()(this.value)
    
    then(successCallback, failCallback)
        // 当没有成功回调时,将value值往下传递
        successCallback = successCallback ? successCallback : value => value;
        // 当没有失败回调时,抛出异常
        failCallback = failCallback ? failCallback : reason =>  throw reason ;
        // 创建一个新的 Promise对象
        let promise2 = new MyPromise((resolve, reject)=>
            // 判断状态
            if(this.status === FULFILLED)
                setTimeout(()=>
                    try 
                        // 定义 val接收成功回调的返回值
                        let x = successCallback(this.value);
                        // resolve(val)


                        // 判断val的值是一个普通值,还是promise对象,
                        // 如果是普通值,直接调用resolve
                        // 如果是promise对象,查看promise对象返回的结果
                        // 再根据promise对象返回的结果,决定调用resolve还是reject
                        resolvePromise(promise2, x, resolve, reject)
                     catch(e) 
                        reject(e)
                    
                    
                ,0)
            else if(this.status === REJECTED)
                setTimeout(()=>
                    try 
                        // 定义 val接收成功回调的返回值
                        let x = failCallback(this.reason)
                        // resolve(val)


                        // 判断val的值是一个普通值,还是promise对象,
                        // 如果是普通值,直接调用resolve
                        // 如果是promise对象,查看promise对象返回的结果
                        // 再根据promise对象返回的结果,决定调用resolve还是reject
                        resolvePromise(promise2, x, resolve, reject)
                     catch(e) 
                        reject(e)
                    
                ,0)
            else 
                // 当异步改变状态时,此时状态为 pending,将成功或失败回调缓存起来
                // 每次调用 then方法 ,都会缓存一个回调
                this.successCallback.push(() => 
                    setTimeout(()=>
                        try 
                            // 定义 val接收成功回调的返回值
                            let x = successCallback(this.value);
                            // resolve(val)
    
                            // 判断val的值是一个普通值,还是promise对象,
                            // 如果是普通值,直接调用resolve
                            // 如果是promise对象,查看promise对象返回的结果
                            // 再根据promise对象返回的结果,决定调用resolve还是reject
                            resolvePromise(promise2, x, resolve, reject)
                         catch(e) 
                            reject(e)
                        
                        
                    ,0)
                )
                this.failCallback.push(() => 
                    setTimeout(()=>
                        try 
                            // 定义 val接收成功回调的返回值
                            let x = failCallback(this.reason)
                            // resolve(val)
    
                            // 判断val的值是一个普通值,还是promise对象,
                            // 如果是普通值,直接调用resolve
                            // 如果是promise对象,查看promise对象返回的结果
                            // 再根据promise对象返回的结果,决定调用resolve还是reject
                            resolvePromise(promise2, x, resolve, reject)
                         catch(e) 
                            reject(e)
                        
                    ,0)
                )
            
        )
        // 返回一个 Promise对象
        return promise2;
    
    catch(failCallback)
        return this.then(undefined, failCallback)
    
    finally(callback)
        // 无论成功或失败都要执行
        return this.then(value=>
            return MyPromise.resolve(callback()).then(() => value)
        ,reason => 
            return MyPromise.resolve(callback()).then(() => throw reason)
        )
    
    static all(array)
        let result = []
        let index = 0 // 由index判断是否执行完所有代码,并将数据添加进result中了
        return new MyPromise((resolve, reject) => 
            // 由addData方法像 result 中添加数据
            function addData(key, val)
                result[key] = val
                index ++
                if(index == array.length)
                    resolve(result)
                
            
            array.forEach((item,index) => 
                if(item instanceof MyPromise)
                    item.then(val => addData(index,val), reason => reject(reason))
                else
                    addData(index,item)
                
            )
        )
    
    static resolve(val)
        // promise对象直接原样返回
        if(val instanceof MyPromise) return val;
        // 数值类型将其作为一个新的promise对象的返回值返回
        return new MyPromise(resolve => resolve(val))
    

function resolvePromise(promise2, x, resolve, reject)
    if(promise2 === x)
        // console.log('传入了同一个promise');
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
    
    if(x instanceof MyPromise)
        // promise对象
        // x.then(value => resolve(value), reason => reject(reason))
        // 优化为:
        x.then(resolve, reject)
    else
        // 普通值
        resolve(x)
    

以上是关于今天教你手写 Promise的主要内容,如果未能解决你的问题,请参考以下文章

说说高频面试题 promise

手写promise啥水平

手写promise啥水平

手写Promise

手写Promise

手写Promise