在JavaScript中,提供了一些异步特性,因为同步操作会对程序的执行进行阻塞处理。比如在
在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对象。
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
Promise对象有以下两个特点。
(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
注意,为了行文方便,本章后面的resolved统一只指fulfilled状态,不包含rejected状态。
有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。
Promise也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
如果某些事件不断地反复发生,一般来说,使用 Stream 模式是比部署Promise更好的选择。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
小程序 请求同步 小程序 同步请求