JS核心--异步编程中的Promise

前言

在JS运行环境中,使用回调函数,来异步编程,会遇到“回调地狱”的问题。为了解决“回调地狱”的问题,我在前面小程序wx.request的封装一文中用到了Promise。 本文则进一步解析异步编程中的Promise的使用,有错误之处,还请指正。

问题

我们先看看什么是回调地狱:

某个异步操作:

fetchGroups(url,success: (res) => {
      fetchActivitiesByGroupId(res.id, success:(res) { 
          fetchActivityRegistered(res.activityId, success:(res)) {
                console.log("this activity is registried).
          }
    })
})

异步获取群组,并传入成功时回调函数;  当回调函数被调用时,在内部再调用获取活动列表并传入一个回调。可见随着嵌套的回调函数越多,代码越加难阅读和维护。

那么有什么办法? Promise则提出了新的想法:把异步操作以看起来像同步的代码写出来。

具体做法:把异步操作的结果保存到promise对象中,  监听异步操作的回调函数不是作为参数一开始就传入异步函数,而是把它们绑定到promise对象上。代码如下所示:

var promise = fetchGroups(url)
var promise2 = promise.then(success: (res)=> fetchActivitiesByGroupId(res.id) })
var promise3 = promise2.then(success: (res) => fetchActivityRegistered(res.id) })
promise3.then((res)=>{ console.log("this activity is registried") })

或者写成链式调用,更简洁:

 fetchGroups(url)
.then(res => fetchActivitiesByGroupId(res.id) })
.then(res => fetchActivityRegistered(res.id) })
.then(res => { console.log("this activity is registried") })

在上面 fetchGroups(url)调用后,添加的第一个then()上绑定的回调函数也返回了一个promise对象,所以我们可以继续在其后继续添加then(),从而形成链式调用。上面绑定的回调函数会按照then方法添加的顺序执行。

异常处理

异常处理分两种情况:

1.Catch()后可以继续链式操作。

异常捕获后,还2可以通过then(),在catch之后,继续绑定新的回调函数,程序能继续执行。

 fetchGroups(url)
.then(res => fetchActivitiesByGroupId(res.id)})
.then(res => fetchActivityRegistered(res.id)})
.then(res => { 
       throw error("got a exception")
       console.log("this activity is registried") 
})
.catch(err => {console.log("catch an error.")}
.then(res => {console.log("I need to update ui, finally.")}

上面代码日志会输出:

line0: "catch an error."
line1: "I need to update ui, finally."

可见,如果在catch之后,继续在回调链上添加函数,依然会得到执行,类似异常处理中的finally代码块的作用。

2.异常的传播链

如果遇到异常被抛出,浏览器/小程序框架会沿着链,找到第一个catch指定的回调函数执行。

 fetchGroups(url)
.then(res => {
      throw error("got a exception")
       return fetchActivitiesByGroupId(res.id) 
})
.then(res => fetchActivityRegistered(res.id)})
.then(res => { 
       console.log("this activity is registried") 
})
.catch(err => {console.log("catch an error.")}

then()遇到异常抛出,则会顺着调用链,查到第一个catch函数,把异常捕获。

输出结果:

"catch an error."

封装旧API

通过创建Promise,我们可以封装旧的api,如封装小程序中的wx.request,使得网络请求支持链式调用:

/**
 * 以HTTP method == GET的方式,发起网络请求。
 * @param {对象参数:可以把多个参数封装到一个对象,作为参数传入函数} params 
 */
const get = (params) => {
    var _token = getApp().getToken()
    return new Promise((resolve, reject) => {
      wx.request({
        method:'GET',
        url: concatUrl(params),
        header:{
          'Authorization': _token,
          'content-type': 'application/json',
        },
        success: (res) => {
          console.log(res)
          checkAuth(res) // 在此处统一拦截token过期,跳转到登录界面
          resolve(res)
        },
        fail:(err) => {
          console.log("请求失败" + err)
          reject(err)
        }
      })
    })
}

Promise常见API

Promise.all() :把多个异步操作组合起来,并发多个操作,等待结果全部返回后,再处理它们。

Promise.all[fun1(),fun2(),fun3()].then(([result1,result2,result3]) => { ... })

总结

本文通过对Promise的使用方法总结,可以理解Promise是如何解决回调地狱的问题,以及它的异常传播链和在抛出异常后继续添加绑定函数,在末尾讲了如何创建Promise来封装旧的API,使得旧API也支持链式调用,最后简单介绍了Promise.all()并发处理多个异步操作并等待它们的结果。

参考链接:

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Using_promises

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值