当前位置: 首页>后端>正文

java给js变量赋值 js变量赋值规则


作者:walkinger

背景

之所以写这篇关于前端的文章,是因为有同事使用JS全局变量不当导致了bug,后端在协助解决时发现了问题所在及由此引发了一些感想。所以在解释标题之前,首先说一下业务背景。

很简单,就是有一个页面可以办理某个业务,这个业务又分为两种类型,可以随意切换类型。发现问题的过程是,页面初始化时默认是A类型,所以此时前端会按照A类型传参调用后台大概3个接口,我们暂且称作接口1,接口2和接口3吧。其中接口3的请求参数依赖接口1和接口2的响应参数,接口1和接口2的返回数据会展示到前端,然后调用接口3时将从接口1和接口2的返回参数中拿数据传递给接口3,然后将接口3返回的数据展示,到此页面初始化加载完成。

由下面页面草图可以看出,接口1,2,3都依赖于类型来完成对应的逻辑处理,在接口调用上肯定是先调接口1,2(二者没有先后顺序),然后调接口3。之后在从A类型切换至B类型时又会重新按B类型重新加载一遍接口1,2,3,展示B类型对应的数据。




java给js变量赋值 js变量赋值规则,java给js变量赋值 js变量赋值规则_ajax,第1张


问题排查

大概的业务规则就是这样的,很简单。但是在测试中发现,当页面初始化时,迅速切换到B类型,前端弹出一个错误窗口“系统错误,缺少必要参数”,偶现的问题但可以稳定复现。

经过排查分析发现是前端接口调用顺序问题,具体点就是调用接口3时,没有拿到需要的数据(接口3的逻辑大致是通过前端传的参数1和参数2取接口1和接口2放在缓存的数据,缓存的Key和类型有关) 从表象上看就是在调用接口3时,接口1或接口2还没有被调用,导致接口3从缓存拿不到需要的数据。

带着这样的疑问去查看前端代码,看接口的调用顺序是不是真的有问题,结果发现前端调用的顺序是没有问题的。那问题是出在哪里呢?

通过排查前端代码,发现一个问题,前端设置了一个全局变量来记录当期的业务类型(如A类型、B类型),调用接口1,2,3传递业务类型时就是传递的这个全局变量。看到这也许你就能想明白为什么说谨慎使用全局变量了,这个问题正是因为全局变量的使用不当导致的。

分析原因

我们来一起分析下到底是如何导致的吧。

上述也提到了初始化时快速切换到B类型,那么前端的这个记录当前业务类型的全局变量是何时改变其值的呢?

没错,正是在切换业务类型时记录当前业务类型A或B。当初始化默认是A类型时,接口会这样调用A类型:接口1(A)->接口2(A)->接口3(A),当切换到B类型时触发一系列接口调用,和A类型也一样,B类型:接口1(B)->接口2(B)->接口3(B)这样调用。

关键就是在切换到B类型时,可能会存在这样的问题,接口1,2正常调用,即传递的业务类型都是A,但恰好在调用接口3前,切换到了业务类型B类型,那么此时记录当前业务类型的全局变量随之变为B,那么此时原本初始化的时候的接口3拿到的业务类型就由预期的A变成了B,而在此之前接口1,2都是按A类型传递的参数,故后台存储的数据是A类型的,但此时因为全局变量的变化,接口3传递的业务类型就又A变为B,故在接口3的业务逻辑里,按业务类型B去缓存取数据时是取不到,后端校验参数时就会报错“系统错误,缺少必要参数”。


java给js变量赋值 js变量赋值规则,java给js变量赋值 js变量赋值规则_全局变量_02,第2张


问题解决

弄懂了发生问题的原因之后怎么来解决呢?其实解决起来也简单,正如标题所说[谨慎使用全局变量],问题的根源就是使用了全局共享变量,导致在A线程还没走完时C线程修改了 biz_type 的值,从而导致线程A的三个步骤拿到的 biz_type 的值不相同,进而导致后台根据类型取缓存数据时拿不到,最终报错。所以,想要解决该问题,最关键的就是从这个全局变量着手,经查看前端代码而知:在切换类型时,根据当前选中的类型传递相应的参数,当选中时我们就能知道是哪种类型了,所以我们就能清楚的去调用接口传递相应的类型字段,而不是先对全局变量赋值,再在接口里自行去取全局变量。
修改前:


var biz_type = 'A';//定义全局变量,默认为A业务类型
//change radio
function changeRadio(){
    if(#('#bizType_A').is(':checked')){
        biz_type = 'A';//修改变量值
        api_1();
    }else{
        biz_type = 'B';//修改变量值
        api_1();
    }   
}
//function1
function api_1(){
    //get biz_type
    //send ajax with biz_typ
    if(data.success){
        api_2();
    }else{
        alert(data.msg);
    }
}
//function2
function api_2(){
    //get biz_type
    //send ajax with biz_typ
    if(data.success){
        api_3();
    }else{
        alert(data.msg);
    }
}
//function3
function api_3(){
    //get biz_type
    //send ajax with biz_type
    if(data.success){
        jump_to_success();
    }else{
        alert(data.msg);
    }
}


修改后:


//change radio
function changeRadio(){
    if(#('#bizType_A').is(':checked')){
        api_1('A');//参数传递
    }else{
        api_1('B');//参数传递
    }   
}
//function1
function api_1(biz_type){
    //send ajax with biz_typ
    if(data.success){data.
        api_2(biz_type);
    }else{
        alert(data.msg);
    }
}
//function2
function api_2(biz_type){
    //send ajax with biz_typ
    if(data.success){
        api_3(biz_type);
    }else{
        alert(data.msg);
    }
}
//function3
function api_3(biz_type){
    //send ajax with biz_type
    if(data.success){
        jump_to_success();
    }else{
        alert(data.msg);
    }
}


修改后使用参数传递的方式,这样可以保证一套流程走下来,拿到的 biz_type 值一样。 另外,可以通过控制切换的方式保证A线程没走完时不允许修改 biz_type 的值,不允许执行B线程,即当A类型下的流程没走完时切换不了类型。可以通过标志位来判定A流程是否走完,进而判定是否可以切换到B类型上。

总结

不过这个问题不大,后端做了参数的校验,但是为了提升用户体验这个问题一定是要解决的。这其实是前端开发人员一个小小的疏忽导致的,当前端在写代码时他肯定不会预见到会发生这样的问题,他肯定没有想到全局变量会导致这样的问题,更不会想到用户在页面没初始化完成时就切换类型。但这些对于一个初出茅庐的前端开发来说,情有可原,权当是积累经验了。切记能传参的尽量不要用全局变量,如果必须要用,那就一点要把握好不要出现类似问题。

事后想想,这个问题如果后端不协助解决、分析日志,想必前端很难发现问题所在吧,所以在实际工作中同事之间要配合好。


https://www.xamrdz.com/backend/3re1963549.html

相关文章: