问题发现

博主暑假被抓去写前端去了,JS其实也就只会写一点点,就是当初学Java Web的时候过了一遍,高级点的用法压根不会,平时做项目也最多改改字段映射,因此在开发过程中遇到了一些莫名其妙的问题。首先博主被安排的工作是改微信小程序的界面Bug,说起来微信小程序也是当初实验室帮老师做项目的时候糊里糊涂地对着文档学了几天,由于后面又没做那个项目了,所以其实微信小程序也没写几天。于是上个星期搞开发的时候就遇到了平时Java开发中从来没有遇到的问题。

首先是我要干的事是根据微信接口获取坐标信息,然后根据坐标信息进行相应处理,代码大概是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var that = this
wx.getLocation({
altitude:true,
success: (res) =>{
var e = {detail:{longitude:res.longitude,latitude:res.latitude}}

// Do Something

that.setData({pos:e})

},
fail: (res) =>{
// 获取定位失败,设置默认值
var e = {detail:{longitude:upStation.longitude,latitude:upStation.latitude}}

// Do Something

that.setData({pos:e})

}
})

var pos = that.data.pos
// 对pos进行处理

代码很简单,看起来无论调用接口成功还是失败,变量pos都应该有值的,但是调试起来我却发现pos始终为空值,习惯于Java开发的我一时间糊涂了,变量的值到底为什么为空呢?仔细观察控制台日志,我忽然发现打印pos时,下面的打印竟然优先于上面的打印,难道说程序并不是一行一行的走下来运行的?上网一搜,在微信官方文档中有这样一段话:

image-20230711153500995

也就是说大部分微信的接口都是异步调用的,在调用获取定位的接口时,程序并不会阻塞而是继续往下执行,这个时候pos变量压根没被赋值,所以就一直报错为空!

问题解决

既然知道是异步调用引起的问题,那么解决方法其实很简单了。用于博主JS水平有限,我讲的肯定没别人明白,参见其他人的博文:js 异步的几种解决方案 - 简书 JS 异步编程的 5 种解决方案 - 掘金,比我讲的更加明白清晰,但是我看总结起来也就几种:

  • 直接把处理逻辑写在异步请求之中,当然这只适用于简单的业务,复杂起来,比如异步里面套异步,回调函数杂揉起来,那简直就是地狱了

  • 使用ES6的Promise,对业务进行链式调用

  • 使用async/await

其实这些问题应该算是前端最基本的要掌握的了,奈何楼主水平有限,也算踩了一次坑吧。

问题拓展

讲到了异步,那为什么要用异步呢?异步和同步又有什么区别呢?完全理解同步/异步与阻塞/非阻塞 - 知乎 上这个回答感觉讲的通俗易懂,总结起来也就是:

  • 异步与同步强调的是消息传递。同步是指调用者主动去监测被调者的状态;异步是指被调者将自己的状态主动告诉它的调用者。
  • 阻塞与非阻塞强调的是执行的返回状态。阻塞就是调用者在调用其他资源的时候直接挂起,等待资源的到来;非阻塞就是调用者直接返回,不等待资源,返回去做其他的事情。

至于在Java中,我所熟悉的就是多线程,创立多线程可以实现异步的效果,至于Java的异步非阻塞框架深入起来内容太多了要讲的了。