在JavaScript中,提供了一些异步特性,因为同步操作会对程序的执行进行阻塞处理。比如在浏览器页面程序中,如果一段同步的代码需要执行很长时间(比如一个很大的循环操作),则页面会产生卡死的现象。
异步为程序提供了性能和体验上的益处,比如可以将代码放到setTimeout()中执行;或者在网页中,我们使用Ajax的方式向服务器端做异步数据请求。这些异步的代码不会阻塞当前的界面主进程,界面还是可以灵活的进行操作,等到异步代码执行完成,再做相应的处理。
举一个例子:在小程序中,我们获取到后台的数据使用时间往往是不定的,这个时候:即使你在前面写的代码,也可能会在后面执行。
function getAccountInfo(callback, errorCallback) { wx.request({ url: '/accounts/12345', success: function (res) { console("1") }, fail: function (res) { //... errorCallback(data); } }); console.log("2") }
也就是存在2输出在1前面的可能。这种策略提升页面加载速度。能很好的提高用户体验感。
但是请看下面的情景:
小程序是提倡不获取用户信息就能使用的,但是在特定的情况下我们必须要拿到用户的一些数据,比如名称,图像链接等等。在这种情况下,我们首先获取用户的code,根据code去后台获取用户的openid或者unionid。拿到这些数据之后我们才能确定用户的身份,然后再去发新的请求(这些请求往往是需要用户身份凭证的,比如Token)。
上面的叙述中,我们发了三次请求,第一次获取code,第二次获取openID或unionid,第三次根据身份信息执行新的请求。我们都知道JS中的请求都是异步执行的,有可能微信服务端的code还没返回,用户已经去执行一些需要权限的操作,这就会导致请求失败。那么小程序该如何解决这种问题呢?这里提供三种方案以供参考:
1.服务端一次请求全部处理。(使用范围太小)
2.客户端在请求成功的回调中,再次发送请求。(可用,但是代码会很冗长且不容易维护)
3.使用Promise
方案一中:比如用户留言功能,我们拿到code和留言内容后全部发给服务端,服务端开启一个新的线程去处理这些业务逻辑,主线程直接返回用户留言成功的提示(这里不考虑新线程执行失败的情况)。
方案二和方案三功能上是相同的,但是代码的展示上可能方案三更加好一些。看下面的代码(其中postReq和getReq是自己封装的请求方法):
var http = require('request.js') function userLogin(name, image, gender, content, artilceId){ //获取code var promise = new Promise(function(resolve,reject){ wx.login({ success: res => { resolve(res.code); } }) }) //获取用户身份凭证 var pm2 = promise.then(function(res){ return new Promise(function (resolve, reject){ http.postReq("user/getUserInfo", { "code": res, "type": 1, "name": name, "image": image, "gender": gender }, function (res) { // console.log(res) if (res.data == "") { wx.showModal({ title: '提示', content: '授权失败,请重试', }) return; } resolve(res); }) }) },function(res){ }) //发表评论 pm2.then(function(res){ // console.log(res.data+":"+content) http.postReq("user/comment", { "content": content, "openId": res.data, "artilceId": artilceId},function(res){ // console.log(res) if(res.data ){ wx.getStorage({ key: 'showInfo', success: function(res) { console.log(res.data ) if(res.data != false){ wx.showModal({ title: '提示', content: '为了维护每天学Java的学习氛围,我们已发邮件提醒管理员对评论进行审核,通过后即可展示您的评论。', }) } },fail:function(res){ wx.setStorage({ key: 'showInfo', data: false, }) wx.showModal({ title: '提示', content: '为了维护每天学Java的学习氛围,我们已发邮件提醒管理员对评论进行审核,通过后即可展示您的评论。', }) } }) } }) }, function(res){ }) } module.exports = { userLogin: userLogin }
这里使用的就是Promise?对于Promise如何使用我们稍后再说,初学阶段我们可能会这样保证同步:
app.postReq("/homework/getHomeWorkLike",{"name":name},function(res){ app.postReq("/homework/getHomeWorkLike",{"name":name},function(res){ app.postReq("/homework/getHomeWorkLike",{"name":name},function(res){ } }) } }) } })
在每次返回成功的回调中执行新的请求,但是当我们处理的业务逻辑过多时候,就会显得很难看。因为不直观,所以不方便我们排查一些错误。所以推荐大家使用Promise。
Promise :
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。