Prudent use of global variables

background

The reason to write this article, because there are colleagues used a global variable improper bug. So before heading to explain, first of all talk about the business background.

It is simply a page can apply for a business, this business is divided into two types, you can switch types. Discovery process of the problem is that the default page initialization type is A, so in this case the front will pass parameters to call back about three interfaces in accordance with the type A, for the time being we are called port 1, port 2 and port 3 bar. 3 wherein the request parameter dependent interfaces Interface 1 and Interface 2 response parameters, the interface 1 and interface 2. The data returned to the front display, and a call interface and passed to the return parameters to get the data interface 2 interfaces from the interface 3 3, then the interface will show the data returned by 3, this initial page load is complete.

As can be seen from the following page sketch, 1,2,3 interfaces depend on the type of process corresponding to completion logic, the interface must be adjusted to 1 (both not order) on the interface calls, then calls the interface 3. After switching from the Type A to Type B Type B will again press again to reload 1,2,3 interfaces, display data corresponding to the B type.

Troubleshooting

Probably this is the business rules, very simple. However, in the test found that when the page is initialized, quickly switch to type B, the front window pops up an error "System error, lack of necessary parameters", the problem can be sporadic but steady reproduction.

After investigation analysis showed a front-end interface problems calling sequence, the specific point is call interface 3, there is no need to get data (interface logic 3 is taken approximately 1 and the interface 2 interfaces the front end in the cache parameter 1 and parameter 2 pass data, and the type of cache Key)
from the appearance point of view is at 3:00 call interface, Interface 1 or Interface 2 has not yet been called, leading to data from the cache interface 3 need not get.

With this question to see the front-end code, see the call sequence interface is not really a problem, and found the front end of the order of calls is no problem. That problem is where is it?

Front-end code through the investigation, found a problem, the front end is provided to a global variable record profit service type (e.g. type A, B type), 1,2,3 transfer call interface when the service type is transmitted global variable. Maybe you'll want to see it to understand why the prudent use of global variables, the problem precisely because of improper use of global variables.

Analyze the reasons

We analyze together under in the end is what caused it.

Mentioned above also quickly switch to the B type initialization, then the front end of the record current service type of the global variable is when to change the value of it?

Yes, it records the current service type A or type B. when switching service When the initialization is the default type A, so that the interface would call Type A: Interface 1 (A) -> Interface 2 (A) -> Interface. 3 (A), triggers a series of interface calls, type A and type B when switching to too, B type: Interface 1 (B) -> Interface 2 (B) -> Interface 3 (B) this call.

When the key is switched to the B type, there may be a problem, the interface 2 normal call, i.e., transfer service type is A, but just before the call to the interface 3, to the service type switching type B, then the time record the current traffic goes in the global variable of type B, then at this time the original initialization of the interface 3 to get the service type B becomes a desired a, but before the interface 1 are by a passed parameter type, so that the background data is stored in the type a, but this time because of changes in global variables, the interface 3 is transmitted to the service type and a to B, so that the interface logic 3 of the business, the business type B take the time to cache data is not eligible, it will error "system error, lack the necessary parameters" when the back-end verification parameters.

 

See this, Do not you think it's a bit like java multi-threaded shared variables? Multi-threaded shared variables can also cause this problem, when a thread is the use of a variable, another thread changed suddenly, causing the thread to get the dirty data. The solution is to thread resource exclusive operation right, the operation is completed other threads have permission to read the resource, at the same time only one thread can modify shared variables, namely among multiple threads in relation to the resources are mutually exclusive relationship, java multi-use locks to ensure the safety of the operation.

那在这个问题中,怎么类比呢?我们可以把选中A类型时要走的一系列接口比作A线程;把B类型要走的一系列接口比作B线程,这两个线程执行的流程、方法一样,只是需要的参数的具体值是不一样的,A、B线程各自执行三个步骤每个步骤都会取共享变量作为参数传递给后台。再把切换类型要改变当前业务类型(`biz_type`)这一操作记作C线程。那大致就是,A、B线程读 `biz_type` ,C线程修改 `biz_type` 。这就可以理解成三个线程共享一个变量,在页面上切换业务类型可以看做线程的轮转,所以不加以控制难免会发生错误。

问题解决

弄懂了发生问题的原因之后怎么来解决呢?其实解决起来也简单,正如标题所说[**谨慎使用全局变量**],问题的根源就是使用了全局共享变量,导致在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类型上。

总结

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

出问题不可怕,在问题中成长,积累经验,才是最重要的。

Guess you like

Origin www.cnblogs.com/ibigboy/p/11119194.html