美文网首页
promise使用初探

promise使用初探

作者: 小人物灌篮 | 来源:发表于2018-12-29 19:44 被阅读6次

    title: promise使用初探
    date: 2018-12-29 16:10:48
    categories: 小游戏
    tags: js


    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,可以大大简化我们回调的嵌套,可以使得我们的代码更加简洁、易读。

    参考资料

    相关文章

      网友评论

          本文标题:promise使用初探

          本文链接:https://www.haomeiwen.com/subject/fuiplqtx.html