promise使用初探

promise简介


Promise是异步编程的一种解决方案,比传统的解决方案 — 回调函数和事件——更合理和更强大。

为什么要用他

我们考虑这么一个场景,我们需要登陆拿到用户的token,然后再利用用户的token取取用户的信息,最后利用用户的相关信息去拿他的好友的相关信息。假设我们提供如下的模拟接口:

class Api{

    getToken(callBack) {
        setTimeout(() =>{
            callBack && callBack("123");
        }, 200);    
    }

    getUserInfo(token, callBack) {
        setTimeout(() => {
            callBack && callBack(token + "4");
        }, 200)
    }

    getOtherInfo(id, callBack) {
        setTimeout(() => {
            callBack && callBack(id + "5");
        }, 200)
    }
}

那么直接用回调来实现的话,我们的调用如下:

var api = new Api();

api.getToken((token) => {
    // 获得了token
    api.getUserInfo(token, (userInfo) => {
        // 获得了userInfo
        api.getOtherInfo(userInfo, (getOtherInfo) => {
            console.log(" get other info " + getOtherInfo);
        })
    })
})

一个很常见的场景,但是我们直接用callBack来实现的话,就会这么多嵌套的回调,这只是一个很简单的例子,试想一下,如果需求更复杂一点的话,回调就会更加复杂,如果要考虑代码的健壮性的话,加上异常处理,那简直就不能忍受了。
在这个时候,promise就站出来了,我们可以通过使用他,大大简化代码的嵌套,避免回调地狱。

promise简单用法

我们稍微调整一下前面的api,我们使用Promise的方式来实现,调整如下:

class Api2{

    getToken() {
        return new Promise((reslove, reject) => {
            setTimeout(() =>{
                reslove && reslove("123");
            }, 200); 
        }) 
    }

    getUserInfo(token) {
        return new Promise((reslove, reject) => {
            setTimeout(() => {
                reslove && reslove(token + "4");
            }, 200)
        })
    }

    getOtherInfo(id) {
        return new Promise((reslove, reject) => {
            setTimeout(() => {
                reslove && reslove(id + "5");
            }, 200)
        })
    }
}

在使用了```Promise``之后,那么我们的调用怎么去调用呢?很简单,如代码所示:

var api = new Api2();

api.getToken().then(function(reslove, reject) {
    console.log("token = "+ reslove);
    api.getUserInfo(reslove).then((reslove, reject) => {
        console.log("info = "+ reslove);
        api.getOtherInfo(reslove).then((reslove, reject) => {
            console.log("friend Id = "+ reslove);
        });
    });
})

可以看到,在使用了Promise之后,代码明显简化了很多。

不知道是怎么看简化的,明显更复杂好吧。
不要着急,我们可以可以一步一步来进行简化。下面开始我们的简化之旅。

promise的链式用法

Promise有一个很棒的特性:Promise.prototype.then()Promise.prototype.catch()返回Promise对象,这就使得我们可以将这些promise连接成一个promise链。通过这种方法,我们可以将这些回调函数放在一个缩进层次里。与此同时,我们使用了箭头函数简化了回调函数声明。
对比之前的回调地狱,使用promise链使得代码的可读性大大提高并且拥有着更好的序列感。

var api = new Api2();

api.getToken().then((reslove, reject) => {
    console.log("token = "+ reslove);
     return api.getUserInfo(reslove);
}).then((userInfo) => {
    return api.getOtherInfo(userInfo);
}).then((friendInfo) => {
    console.log("friend id = " + friendInfo);
});

是不是明显就没有那么多回调了,看着是不是舒服多了。哈哈,不过这还没完,这代码看起来还是稍微有点复杂,虽然没有一层一层的回调了,但是链起来好像也有点长,让我们继续来优化他。

使用Async/Await将异步“变”同步

我们首先来看调用的函数代码:

async function getFriend() {
    const api = new Api2();
    const token = await api.getToken();
    const userInfo = await api.getUserInfo(token);
    const friend = await api.getOtherInfo(userInfo);
    console.log("friend " + friend);
}


是不是顿时感觉就清爽很多了。
我们可以通过await将回调“变”成同步方法来使用,我们只有执行完了api.getToken之后,才能继续执行下面的方法。前提是必须要在异步方法里,即被async修饰的方法里面。从上面的方法来说,我们可以将它当作一个同步方法来使用了。

并行处理

前面的方法,将异步方法"变"成了同步方法,如果我们想异步并行请求数据该怎么办呢?


异常处理

我们先来看,如果使用回调的话,如果要进行异常处理该怎么写吧。

var api = new Api();

try{
    api.getToken((token) => {
        // 获得了token
        try{
            api.getUserInfo(token, (userInfo) => {
                // 获得了userInfo
                try{
                    api.getOtherInfo(userInfo, (getOtherInfo) => {
                        console.log(" get other info error" + getOtherInfo);
                    })
                } catch(e) {
                    console.log("getOtherInfo " + e);
                }
            })
        } catch(e) {
            console.log("getUserInfo error" + e);
        }
    })    
} catch(e) {
    console.log("getToken error" + e);
}

这么多try-catch,是不是双爽歪歪,如果我们还要加入流程控制、异常处理,这简直就是异常灾难。那么我们接下来看怎么用Promise进行异常处理。

先上代码:

api.getToken().then((reslove, reject) => {
    console.log("token = "+ reslove);
     return api.getUserInfo(reslove);
}).then((userInfo) => {
    return api.getOtherInfo(userInfo);
}).then((friendInfo) => {
    console.log("friend id = " + friendInfo);
}).catch((err) =>  {
    console.log("error " + err);
});

链式的调用,我们只需要在在后面加上一条异常处理的catch()即可,和前面的若干个try-catch相比是不是简单很多。当然,我们也可以用awit-async组合+try-catch来处理异常。示例代码如下:

async function getFriend() {
    try{
        const api = new Api2();
        const token = await api.getToken();
        const userInfo = await api.getUserInfo(token);
        const friend = await api.getOtherInfo(userInfo);
        console.log("friend " + friend);
    } catch(e) {
        console.error("error: "+ e);
    } 
}

总结

通过使用Promise,可以大大简化我们回调的嵌套,可以使得我们的代码更加简洁、易读。

参考资料

根据原作 https://pan.quark.cn/s/0ed355622f0f 的源码改编 野火IM解决方案 野火IM是专业级即时通讯和实时音视频整体解决方案,由北京野火无限网络科技有限公司维护和支持。 主要特性有:私有部署安全可靠,性能强大,功能齐全,全平台支持,开源率高,部署运维简单,二次开发友好,方便与第三方系统对接或者嵌入现有系统中。 详细情况请参考在线文档。 主要包括一下项目: 野火IM Vue Electron Demo,演示如何将野火IM的能力集成到Vue Electron项目。 前置说明 本项目所使用的是需要付费的,价格请参考费用详情 支持试用,具体请看试用说明 本项目默认只能连接到官方服务,购买或申请试用之后,替换,即可连到自行部署的服务 分支说明 :基于开发,是未来的开发重心 :基于开发,进入维护模式,不再开发新功能,鉴于已经终止支持且不再维护,建议客户升级到版本 环境依赖 mac系统 最新版本的Xcode nodejs v18.19.0 npm v10.2.3 python 2.7.x git npm install -g node-gyp@8.3.0 windows系统 nodejs v18.19.0 python 2.7.x git npm 6.14.15 npm install --global --vs2019 --production windows-build-tools 本步安装windows开发环境的安装内容较多,如果网络情况不好可能需要等较长时间,选择早上网络较好时安装是个好的选择 或参考手动安装 windows-build-tools进行安装 npm install -g node-gyp@8.3.0 linux系统 nodej...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值