【前端】一文彻底学会Promise

296 阅读5分钟

作者:D827

来源:恒生LIGHT云社区

没有一个功能是看了源码后,还不会用的。所以看完本篇文章,希望能帮助你彻底掌握Promise。

Promise的介绍

Promise对象是ES6提供的实现异步的一个解决方案,它使得异步方法可以像同步方法那样返回值。

promise是一个构造函数包裹(封装) 一个异步函数(ajax;定时器;数据库读取;fs文件读取),当然它也可以包裹一个非异步函数。入参为两个函数resolve、reject。成功调用resolve,并传递参数,失败调用reject,并传递参数。使用.then来作为回调结果的处理,then接受两个函数参数,第一个参数接受正确的返回结果,第二个函数接收错误的返回结果。

Promise三种状态:pending、fullfilled/resolved、rejected

Promise初始状态为pending,通过resolve方法将状态修改为fullfilled/resolved;通过reject将状态修改为rejected

promise的优点:它能够实现链式调用,解决了回调实现异步导致的回调地狱问题。

promise的缺点:

  1. 无法监测进行状态、新建立即执行且无法取消;
  2. 如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部;
  3. 有时会造成多个 then 的链式调用,可能会造成代码的语义不够明确。

Promise的基本使用

function sleep(data){
   return new Promise((resolve,reject)=>{
   // new Promise 包裹的可以是一个异步的代码,也可以是一个同步的代码
   // 代码执行成功
       setTimeOut(()=>{
          let result = null
           if(1){
             resolve(result)  
          }else{
              reject(result) 
          } 
      },1000)
})
}
sleep(1000).then(v=>{
   // 正确返回处理
},e=>{
  // 错误返回处理
}).then(v=>{
 
}).then(v=>{
 
})
……
.catch(e=>{
   // 错误处理
})

自定义Promise需要注意的问题,及解答

  1. promise如何修改状态

    通过调用resolve、reject修改状态

  2. 多次调用resolve、reject可以修改状态吗

    不可以,当从pending修改为resolved或者rejected后无法再次修改为其他状态

  3. promise是先修改状态还是显示执行then,以及什么时候得到数据

    两种情况都可能出现,当promise包裹的内容为异步时先指定then再修改状态,反之先修改状态再执行then;

    数据是在执行完回调后获取。

  4. promise.then返回一个promise,这个返回的类型结果由谁决定

    返回的为promise,由返回的promise决定

    返回为非promise,则返回为resolved

  5. promise如何串联多个操作任务

    因为promise.then返回的是一个新的Promise对象,所以还可以调用then,实现链式调用

  6. promise异常穿透

    意思是不论有多少个then,中间任意一个then出现报错都会被catch捕获

  7. 如何终止promise链

    then中任意一个出现异常;

    在任意then中将promise的状态改为pending。

Promise的自定义

//声明构造函数
function Promise(executor){
    //添加属性
    this.PromiseState = 'pending';
    this.PromiseResult = null;
    //声明属性 回调存在多个情况
    this.callbacks = [];
    //保存实例对象的 this 的值
    const self = this;// self _this that
    //resolve 函数
    function resolve(data){
        //判断状态 多次调用resolve、reject不可以修改状态
        if(self.PromiseState !== 'pending'return;
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = 'fulfilled';// resolved
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data;
        //调用成功的回调函数
        setTimeout(() => {
            self.callbacks.forEach(item => {
                item.onResolved(data);
            });
        });
    }
    //reject 函数
    function reject(data){
        //判断状态
        if(self.PromiseState !== 'pending'return;
        //1. 修改对象的状态 (promiseState)
        self.PromiseState = 'rejected';// 
        //2. 设置对象结果值 (promiseResult)
        self.PromiseResult = data;
        //执行失败的回调
        setTimeout(() => {
            self.callbacks.forEach(item => {
                item.onRejected(data);
            });
        });
    }
    try{
        //同步调用『执行器函数』
        executor(resolve, reject);
    }catch(e){
        //修改 promise 对象状态为『失败』
        reject(e);
    }
}

//添加 then 方法
Promise.prototype.then = function(onResolved, onRejected){
    const self = this;
    //判断回调函数参数
    if(typeof onRejected !== 'function'){
        onRejected = reason => {
            throw reason;
        }
    }
    if(typeof onResolved !== 'function'){
        onResolved = value => value;
        //value => { return value};
    }
    return new Promise((resolve, reject) => {
        //封装函数
        function callback(type){
            try{
                //获取回调函数的执行结果
                let result = type(self.PromiseResult);
                //判断
                if(result instanceof Promise){
                    //如果是 Promise 类型的对象
                    result.then(v => {
                        resolve(v);
                    }, r=>{
                        reject(r);
                    })
                }else{
                    //结果的对象状态为『成功』
                    resolve(result);
                }
            }catch(e){
                reject(e);
            }
        }
        //调用回调函数 PromiseState
        if(this.PromiseState === 'fulfilled'){
            setTimeout(() => {
                callback(onResolved);
            });
        }
        if(this.PromiseState === 'rejected'){
            setTimeout(() => {
                callback(onRejected);
            });
        }
        //判断 pending 状态
        if(this.PromiseState === 'pending'){
            // 异步情况下保存回调函数 在异步执行结束后执行回调函数
            this.callbacks.push({
                onResolvedfunction(){
                    callback(onResolved);
                },
                onRejectedfunction(){
                    callback(onRejected);
                }
            });
        }
    })
}

//添加 catch 方法
Promise.prototype.catch = function(onRejected){
    return this.then(undefined, onRejected);
}

//添加 resolve 方法
Promise.resolve = function(value){
    //返回promise对象
    return new Promise((resolve, reject) => {
        if(value instanceof Promise){
            value.then(v=>{
                resolve(v);
            }, r=>{
                reject(r);
            })
        }else{
            //状态设置为成功
            resolve(value);
        }
    });
}

//添加 reject 方法
Promise.reject = function(reason){
    return new Promise((resolve, reject)=>{
        reject(reason);
    });
}

//添加 all 方法
Promise.all = function(promises){
    //返回结果为promise对象
    return new Promise((resolve, reject) => {
        //声明变量
        let count = 0;
        let arr = [];
        //遍历
        for(let i=0;i<promises.length;i++){
            //
            promises[i].then(v => {
                //得知对象的状态是成功
                //每个promise对象 都成功
                count++;
                //将当前promise对象成功的结果 存入到数组中
                arr[i] = v;
                //判断
                if(count === promises.length){
                    //修改状态
                    resolve(arr);
                }
            }, r => {
                reject(r);
            });
        }
    });
}

//添加 race 方法
Promise.race = function(promises){
    return new Promise((resolve, reject) => {
        for(let i=0;i<promises.length;i++){
            promises[i].then(v => {
                //修改返回对象的状态为 『成功』
                resolve(v);
            },r=>{
                //修改返回对象的状态为 『失败』
                reject(r);
            })
        }
    });
}

希望以上内容对你有所帮助!


想向技术大佬们多多取经?开发中遇到的问题何处探讨?如何获取金融科技海量资源?

恒生LIGHT云社区,由恒生电子搭建的金融科技专业社区平台,分享实用技术干货、资源数据、金融科技行业趋势,拥抱所有金融开发者。