在一个测试工具开发中,发现在批量生成数据的过程中存在数据异常问题。
批量生成数据的逻辑设计是:根据要生成案件的数量,通过循环体调用ajax,反复调用Controller里的/batchGenerator接口,每次调用根据限制条件生成一个符合条件的单据。
由于ajax的异步特性,出现数据异常大概率是在这个过程中存在多线程问题,需要在ajax过程中加以控制防止数据异常。最初的尝试:先改一行代码,把ajax方法改成同步的。
改完后相关代码如下(老版本代码只剩下截图了,凑合着看):
运行了一下发现,数据倒是立马变正常了~然鹅,,,,,,,,
整个页面完全卡住了Σ(o゚д゚oノ),这和想象中的完全不一样哇。。。。
明明应该点击按钮后置灰按钮,然后进入循环后,先更新页面进度条,再发同步请求,结束后判断数量是否满足,继续循环或结束的,
结果别说是每次循环刷新进度条了,连写在100行之前的点击按钮后置灰按钮的代码都完全没生效!(╯°□°)╯︵┻━┻
查了一下ajax同步方法的特点后发现,js本身是单线程的。
ajax同步方法会占用线程而阻塞UI渲染的进度,而script函数的执行优先级又高于页面UI加载(比如在页面scrpit里写一个alert,加载页面时先跳出alert,关闭后才出页面)
所以虽然UI渲染代码写在前面,但在ajax同步面前统统被打住(ಥ_ಥ),这页面效果实在是无法接受啊。。。
谷歌了一下“ajax同步 UI线程阻塞”,找到了一丝光明:deferred对象。
defferd对象是一种基于promise的异步流控制对象,是一种jQuery的回调函数解决方案,学习了一下阮一峰的日志
http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html ,
对代码进行第二次修改:
这样可以将ajax方法设为异步,然后通过done或者fail方法进行类似同步的控制。再次尝试之后发现页面不卡了(~ ̄▽ ̄)~
但是数据TM又出现异常了 щ(゚Д゚щ)。。。。。
仔细思考一番之后幡然醒悟,关键问题好像是在于ajax方法是写在一个循环体内反复调用的。
所以在ajax设回异步之后,循环体执行不会再被卡住了,所以丝滑的连续发起请求。
而ajax推送及返回结果的过程则存在延时,于是又引起了数据的异常。
所以绕了一圈这么改和原来用success,error是一个样(╯-_-)╯~╩╩
因而要解决这个问题,就要确保一次ajax请求完成之后再发起下一次,而不能简单粗暴的仍到循环体里。。。。
这下就不是改一两个代码就能解决的了(ಥ_ಥ),得对这块逻辑重构一下:
于是ajax请求就被放到了一个递归函数里面,count和batchNum这两个变量控制进度,一次请求完成之后如果进度没有结束,则count自增并递归调用。
再次运行发现,页面不卡了,数据也正常了(๑•̀ㅂ•́)و✧