promise使用初探


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

参考资料

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268