温故知新(七二)介绍下 Promise 的特性、优缺点,内部是如何实现的,动手实现 Promise

介绍下 Promise 的特性、优缺点,内部是如何实现的,动手实现 Promise

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

答案:

一、Promise 基本特性

1. Promise 有三种状态:pending (进行中),fulfilled (已成功),rejected (已失败)

2. Promise 对象接受一个回调函数作为参数,该回调函数接受两个参数,分别是成功时的回调 resolve 和 失败时的回调 reject;另外 resolve 的参数除了正常值以外,还可能是一个 Promise 对象的实例;reject 的参数通常是一个 Error 对象的实例

3. then 方法返回一个新的 Promise 实例,并接受两个参数 onResolved ( fulfilled 状态的回调),onRejected ( rejected 状态的回调,该参数可选)

4. catch 方法返回一个新的 Promise 实例

5. finally 方法不管 Promise 状态如何都会执行,该方法的回调函数不接受任何参数

6. Promise.all() 方法将多个 Promise 实例包装成一个新的 Promise 实例,该方法接受一个由 Promise 对象组成的数组作为参数 (Promise.all() 方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例),注意参数中只要有一个实例触发 catch 方法,都会触发 Promise.all() 方法返回的新实例的 catch 方法,如果参数中的某个实例本身调用了 catch 方法,将不会触发 Promise.all() 方法返回的新实例的 catch 方法

7. Promise.race() 方法的参数与 Promise.all() 方法一样,参数中的实例只要有一个率先改变状态就会将该实例的状态传给 Promise.race() 方法,并将返回值作为 Promise.race() 方法产生的 Promise 实例的返回值

8. Promise.resolve() 将现有对象转为 Promise 对象,如果该方法的参数为一个 Promise 对象,Promise.resolve() 将不做任何处理;如果参数是 thenable 对象(即具有 then 方法),Promise.resolve() 方法将该对象转为 Promise 对象并立即执行 then 方法;如果参数是一个原始值,或者是一个不具有 then 方法的对象,则 Promise.resolve() 返回一个新的 Promise 对象,状态为 fulfilled,其参数将作为 then 方法中 onResolved 回调函数的参数。如果 Promise.resolve() 方法不传入参数,会直接返回一个 fulfilled 状态的 Promise 对象。需要注意的是,立即 resolve() 的 Promise 对象,是在本轮“事件循环(event loop)”结束时执行,而不是在下一轮“事件循环”的开始时执行

9. Promise.reject() 同样返回一个新的 Promise 对象,状态为 rejected,无论传入任何参数都将作为 reject() 的参数

二、Promise 的优点

1.统一的异步 API

Promise 的一个重要优点是它将逐渐被用作浏览器的异步 API ,统一现在各种各样的 API ,以及不兼容的模式和写法。

2. Promise 与事件对比

和事件相比较,Promise 更适合处理一次性的结果,在结果计算出来之前或之后注册回调函数都是可以的,都可以拿到正确的值。Promise 的这个优点很自然。但是,不能使用 Promise 处理多次触发的事件。链式处理是 Promise 的又一优点,但是事件却不能这样链式处理。

3. Promise 和回调对比

解决了回调地狱的问题,将异步操作以同步操作的流程表达出来。

4. Promise 带来的额外的好处是包含了更好的错误处理方式(包含了异常处理),并且写起来很轻松(因为可以重用一些同步工具,比如 Array.prototype.map())。

三、Promise 的缺点

1.无法取消 Promise,一旦新建它就会立即执行,无法中途取消。

2.如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。

3.当处于 pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

4. Promise 真正执行回调的时候,定义 Promise 那部分实际上已经执行完了,所以 Promise 的报错堆栈上下文不太友好

四、简单代码实现,最简单的 Promise 实现有 7 个主要属性,state(状态),value(成功返回值),reason(错误信息),resolve 方法,reject 方法,then 方法。

class Promise{
    constructor(executor){
        this.state = 'pending';
        this.value = undefined;
        this.reason = undefined;
        let resolve = value=>{
            if(this.state === 'pending'){
                this.state = 'fulfilled';
                this.value = value;
            }
        };
        let reject = value=>{
            if(this.state === 'pending'){
                this.state = 'rejected';
                this.reason = value;
            }
        };
        try{
            //立即执行函数
            executor(resolve,reject);
        }catch(err){
            reject(err);
        }
    }
    then(onFulfilled,onRejected){
        if(this.state === 'fulfilled'){
            typeof onFulfilled === 'function' && onFulfilled(this.value);
        };
        if(this.state === 'rejected'){
            typeof onRejected === 'function' && onRejected(this.reason);
        };
    }
    
}

测试:

m = new Promise(resolve=>{
    console.log('aaa')
    setTimeout(function(){
        resolve(9000)
    }, 2000)

})
m.then(res=>console.log(res));//执行

运行起来我们发现只打印了构造函数中的 aaa 而 异步 then  方法并没有执行。

流程如下:

当then里面函数运行时,resolve由于是异步执行的,还没有来得及修改state,此时还是PENDING状态;因此我们需要对异步的情况做一下处理。

进阶版:

class Promise{
    constructor(executor){
        this.state = 'pending';
        this.value = undefined;
        this.reason = undefined;
        this.onFulfilled = [];
        this.onRejected = [];

        try{
            executor(this.resolve,this.reject);
        }catch(e){
            this.reject(e);
        }
        
    }
    resolve = (res)=>{
        if(this.state === 'pending'){
            this.state = 'fulfilled';
            this.value = res;
            this.onFulfilled.forEach(fn=>fn(res));
        }
    }

    reject = (res)=>{
        if(this.state === 'pending'){
            this.state = 'rejected';
            this.reason = res;
            this.onRejected.forEach(fn=>fn(res));
        }
    }

    then = (onFulfilled,onRejected)=>{
        if(this.state === 'fulfilled'){
            typeof onFulfilled === 'function' && onFulfilled(this.value);
        }
        if(this.state === 'rejected'){
            typeof onRejected === 'function' && onRejected(this.value);
        }
        if(this.state === 'pending'){
            typeof onFulfilled === 'function' && this.onFulfilled.push(onFulfilled);
            typeof onRejected === 'function' && this.onRejected.push(onRejected);
        }
    }
}

 但是没有实现链式调用

详细版:

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
function Promise(executor){
    let that = this; //缓存当前的promise 对象
    this.status = PENDING; //初始状态
    that.value = undefined; //fulfilled 状态时 返回的信息
    that.reason = undefined; // rejected 状态时 拒绝的原因
    that.onFulfilledCallbacks = []; // 存储fulfilled状态对应的 onFulfilled 函数
    that.onRejectedCallbacks = []; //存储 rejected状态对应的 onRejected函数

    //value 成功状态时接受的终值
    function resolve(value){
        if(value instanceof Promise){
            return value.then(resovle,reject);
        }
        //实践中药确保 onFulfilled 和 onRejected 方法异步执行,且应该在
        // then 方法被调用的那一轮事件循环之后的新执行栈中执行
        setTimeout(()=>{
            if(that.status === PENDING){
                //只能由pending状态转为 fulfilled 状态(避免调用多次resolve,reject)
                that.status = FULFILLED;
                that.value = value;
                that.onFulfilledCallbacks.forEach(cb=>cb(that.value));
            }
        });
    }
    //reason 失败状态时拒绝的原因
    function reject(reason){
        setTimeout(()=>{
            //调用reject回调对应的onRejected的函数
            if(that.status === PENDING){
                //只能由pending状态转为 fulfilled 状态(避免调用多次resolve,reject)
                that.status = REJECTED;
                that.reason = reason;
                that.onRejectedCallbacks.forEach(cb=>cb(that.reason));
            }
        });
    }
    //捕获在excutor 执行器中抛出的异常
    // new Promise((resolve,reject)=>{
    //     throw new Error('error in excutor');
    // })
    try{
        executor(resolve,reject);
    }catch(e){
        reject(e);
    }
}
Promise.prototype.then = function(onFulfilled,onRejected){
    const that = this;
    let newPromise;
    //处理参数默认值,保证参数后续能够继续执行
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason =>{throw reason};

    //成功状态
    if(that.status === FULFILLED){
        return newPromise = new Promise((resolve,reject)=>{
            setTimeout(()=>{
                try{
                    let x = onFulfilled(that.value);
                    //新的promise resolve上一个onFulfilled的返回值
                    resolvePromise(newPromise,x,resolve,reject);
                }catch(e){
                    //捕获前面的onFulfilled中抛出的异常then(onFulfilled,onRejected);
                    reject(e);
                }
            });
        });
    }
    //失败状态
    if(that.status === REJECTED){
        return newPromise = new Promise((resolve,reject)=>{
            setTimeout(()=>{
                try{
                    let x = onRejected(that.reason);
                    resolvePromise(newPromise,x,resolve,reject);
                }catch(e){
                    reject(e);
                }
            });
        });
    }
    //等待状态
    if(that.status === PENDING){
        //当异步调用 resolve/reject时,将onFulfilled/onRejected收集暂存到集合中
        return newPromise = new Promise((resolve,reject)=>{
            that.onFulfilledCallbacks.push((value)=>{
                try{
                    let x = onFulfilled(value);
                    resolvePromise(newPromise,x,resolve,reject);
                }catch(e){
                    reject(e);
                }
            });
            that.onRejectedCallbacks.push((reason)=>{
                try{
                    let x = onRejected(reason);
                    resolvePromise(newPromise,x,resolve,reject);
                }catch(e){
                    reject(e);
                }
            });
        });
    }
}


function resolvePromise(promise2, x, resolve, reject){
    if(promise2 === x){
        reject(new TypeError('Chaining cycle'))
    }
    if(x && typeof x === 'object' || typeof x === 'function'){
        let used;
        try {
            let then = x.then
            if(typeof then === 'function'){
                then.call(x, (y)=>{
                    if (used) return;
                    used = true
                    resolvePromise(promise2, y, resolve, reject)
                }, (r) =>{
                    if (used) return;
                    used = true
                    reject(r)
                })
            } else {
                if (used) return;
                used = true
                resolve(x)
            }
        } catch(e){
            if (used) return;
            used = true
            reject(e)
        }
    } else {
        resolve(x)
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值