promise原理及简单实现

谈谈promise

promise是es6提供的异步编程解决方案,相比之前的回调函数方案更加合理强大。

promise是一种异步流程的控制手段,下面几个promise特点

1、避免了回调地狱,可链式调用。

2、支持多个并发请求,获取并发请求数据。

3、promise可以解决异步的问题,但不能说promise本身就是异步的。

4、promise三种状态:pending,resolved,rejected,状态只能是pending到resolved或者pending到rejected,不能是resolved到rejected或者rejected到resolved。状态一旦改变就不会再变,且状态不可逆。

5、Promise对象是一个构造函数,只有一个参数叫executor执行器,默认new的时候就会调用。

promise缺点:

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

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

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

 

promise雏形

先写MyPromise类的构造函数,里面有的私有成员

state ------ Promise当前状态

value ------ 最终我们要的执行结果(数据)

Promise第一个参数(回调函数)立即执行,是同步的,真正异步的在then()

class MyPromise{
    constructor(executor){
        this.state = 'pending';
        this.value = null;
        //resolve函数
        let resolve = result => {
            if(this.state !== 'pending') return;  //状态只能从等待态到成功态
            this.state = 'fulfilled';
            this.value = result;
        }
        //reject函数
        let reject = reason => {
            if(this.state !== 'pending') return;  //状态只能从等待态到失败态
            this.state = 'rejected';
            this.value = reason;
        }
        //executor立即执行,如果执行出错则走reject
        try{
            executor(resolve, reject);
        }catch(err){
            reject(err);
        }
    }
}

then()

上面我们知道,Promise有执行结果会调用resolve,执行出错会调用reject。但真正拿到执行结果再进行处理的在then()。

then(successFn, failFn) ,有两个参数,我简单粗暴的以successFn、failFn命名,当resolve被调用时会执行successFn,而reject被调用时hi执行failFn。

所以JS代码执行到then()实际只是将successFn和failFn存储起来,静静等待被调用。

所以在构造函数里加两个容器用于存放successFn和failFn

class MyPromise{
    constructor(executor){
        ...
        this.successQueue = [];
        this.failQueue = [];
        //resolve函数
        let resolve = result => {
            ...
            this.successQueue.forEach(item => {
                item(this.value)
            })
        }
        //reject函数
        let reject = reason => {
            ...
            this.failQueue.forEach(item => {
                item(this.value);
            })
        }
    }
    then(successFn, failFn){
        this.successQueue.push(successFn);
        this.failQueue.push(failFn);
    }
}

到这里就简单的实现了then(),现在可以简单的使用。但有一个问题,如果Promise里没有进行一步操作而是直接resolve或reject的话,上面的封装可能会出现问题,比如:

new MyPromise((resolve, reject) => {
    resolve('haha')
}).then(res => {
    console.log(res)
}, err => {
    console.log(err)
})

结果没有任何输出,这是因为我们上面的封装,在resolve执行时,then的successFn和failFn都还没放进容器里。

实际上then里的successFn和failFn始终是异步执行的,也就是微任务。这里我们可以用setTimeout包一下,达成那种效果

class MyPromise{
    constructor(executor){
        ...
        //resolve函数
        let resolve = result => {
            ...
            let timer = setTimeout(() => {
                clearTimeout(timer);
                this.successQueue.forEach(item => {
                    item(this.value)
                })
            }, 0)
        }
        //reject函数
        let reject = reason => {
            ...
            let timer = setTimeout(() => {
                clearTimeout(timer);
                this.failQueue.forEach(item => {
                    item(this.value)
                })
            }, 0)
        }
    }
    ...
}

 

链式then()

说到链式调用,不用想,then()肯定是返回一个Promise。注意点:

第一个then的successFn或failFn执行有结果会走到第二个then的successFn,第一个then的successFn或failFn执行出错会走到第二个then的failFn。如此类推

class MyPromise{
    constructor(executor){
        ...
    }
    then(successFn, failFn){
        return new MyPromise((resolve, reject) => {
            //在successFn和failFn外再包一层函数,这样resolve()或reject()时实际会执行该函数
            //在该函数里判断当前successFn或failFn的结果,然后再resolve()或reject()给下一个then
            this.successQueue.push(() => {
                try{
                    let x = successFn(this.value);
                    //如果successFn返回一个Promise,则执行该Promise的then方法即可
                    x instanceof MyPromise ? x.then(resolve, reject) : resolve(x);
                }catch(err){
                    reject(err);
                }
            })
            this.failQueue.push(() => {
                try{
                    let x = failFn(this.value);
                    x instanceof MyPromise ? x.then(resolve, reject) : resolve(x);
                }catch(err){
                    reject(err);
                }
            })
        })
    }
}

到这里还要考虑一个问题,就是then方法参数默认值问题,如果then方法中没有传参的话,事实上要将promise执行结果传到下一个then处理。所以then方法中的successFn和failFn应该有默认值successFn默认值是一个有返回值的函数而failFn需要注意,我们要想在下一个then的failFn处理错误的话,那么当前的failFn就必须reject

then(successFn, failFn){
    typeof successFn !== 'function' ? successFn = result => result : null;
    return new MyPromise((resolve, reject) => {
        typeof failFn !== 'function' ? failFn = reason => reject(reason) : null;
        ...
    })
}

 

catch()

catch方法原理极其简单,比如Promise出错,第一个then(successFn, null),第二个then(null, failFn),没错,catch方法就是第二个then,一模一样

catch(failFn){
    return this.then(null, failFn);
}

 

Promise.all()

原理也不难,也是返回一个Promise,只不过这个Promise里的异步操作是等一串Promise任务都完成了才resolve,而如果其中有一个出错了,那就reject

static all(promiseArr = []){
    return new MyPromise((resolve, reject) => {
        let n = 0;
        let result = [];
        let errFlag = false;
        for(let i=0; i<promiseArr.length; i++){
            //如果有一个Promise出错了,那就结束循环
            if(errFlag) break;
            promiseArr[i].then(res => {
                n++;
                result[i] = res;
                //如果结果数量等于promiseArr.length,那就resolve
                if(n === promiseArr.length)} resolve(result);
            }, err => {
                errFlag = true;
                reject(err);
            })
        }
    })
}

至此,大致完成了自己封装的Promise,肯定没有原生的完善,基本功能都实现了。

完整代码

class MyPromise{
    constructor(executor){
        this.state = 'pending';
        this.value = null;
        this.successQueue = [];
        this.failQueue = [];
        let resolve = result => {
            if(this.state !== 'pending') return;
            // then中的函数总是异步执行的
            this.state = 'fulfilled';
            this.value = result;
            let timer = setTimeout(() => {
                clearTimeout(timer);
                this.successQueue.forEach(item => {
                    item(this.value);
                })
            }, 0)
        }
        let reject = reason => {
            if(this.state !== 'pending') return;
            // then中的函数总是异步执行的
            this.state = 'rejected';
            this.value = reason;
            let timer = setTimeout(() => {
                clearTimeout(timer);               
                this.failQueue.forEach(item => {
                    item(this.value);
                })
            }, 0);
        }
        // 执行器立即执行
        try{
            executor(resolve, reject);
        }catch(err){
            //如果一开始执行器出错就走reject
            reject(err);
        }
    }

    then(successFn, failFn){
        typeof successFn !== 'function' ? successFn = result => result : null;
        return new MyPromise((resolve, reject) => {
            this.successQueue.push(() => {
                try{
                    let x = successFn(this.value);
                    x instanceof MyPromise ? x.then(resolve, reject) : resolve(x);
                }catch(err){
                    reject(err);
                }
            });

            typeof failFn !== 'function' ? failFn = reason => reject(reason) : null;
            this.failQueue.push(() => {
                try{
                    let x = failFn(this.value);
                    x instanceof MyPromise ? x.then(resolve, reject) : resolve(x);
                }catch(err){
                    reject(err);
                }
            });
        })
    }

    catch(failFn){
        return this.then(null, failFn);
    }

    static all(promiseArr){
        return new MyPromise((resolve, reject) => {
            let result = [];
            let n = 0;
            let errFlag = false;
            for(let i=0; i<promiseArr.length; i++){
                if(errFlag) break;
                promiseArr[i].then(res => {
                    result[i] = res;
                    n++;
                    if(n === promiseArr.length){
                        resolve(result);
                    }
                }, err => {
                    errFlag = true;
                    reject(err);
                })
            }
        })
    }
}

 

promise面试题

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Promise是一种用于处理异步操作的JavaScript对象。它提供了一种更优雅和可读性更高的方式来处理异步代码,避免了回调地狱的问题。Promise有三个状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。当Promise的状态发生改变时,会触发相应的回调函数。 以下是一个简单Promise实现原理的例子: ```javascript class MyPromise { constructor(executor) { this.status = 'pending'; this.value = undefined; this.reason = undefined; this.onResolvedCallbacks = []; this.onRejectedCallbacks = []; const resolve = (value) => { if (this.status === 'pending') { this.status = 'fulfilled'; this.value = value; this.onResolvedCallbacks.forEach((callback) => callback()); } }; const reject = (reason) => { if (this.status === 'pending') { this.status = 'rejected'; this.reason = reason; this.onRejectedCallbacks.forEach((callback) => callback()); } }; try { executor(resolve, reject); } catch (error) { reject(error); } } then(onFulfilled, onRejected) { onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => value; onRejected = typeof onRejected === 'function' ? onRejected : (reason) => { throw reason; }; const promise2 = new MyPromise((resolve, reject) => { if (this.status === 'fulfilled') { setTimeout(() => { try { const x = onFulfilled(this.value); this.resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0); } if (this.status === 'rejected') { setTimeout(() => { try { const x = onRejected(this.reason); this.resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0); } if (this.status === 'pending') { this.onResolvedCallbacks.push(() => { setTimeout(() => { try { const x = onFulfilled(this.value); this.resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0); }); this.onRejectedCallbacks.push(() => { setTimeout(() => { try { const x = onRejected(this.reason); this.resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0); }); } }); return promise2; } resolvePromise(promise2, x, resolve, reject) { if (promise2 === x) { return reject(new TypeError('Chaining cycle detected for promise')); } if (x instanceof MyPromise) { x.then(resolve, reject); } else { resolve(x); } } catch(onRejected) { return this.then(null, onRejected); } } ``` 这个例子展示了一个简单Promise实现,包括Promise的构造函数、状态的改变、回调函数的执行、链式调用以及错误处理等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值