13.ajax同步与异步

来源:互联网 发布:中信淘宝会员卡 编辑:程序博客网 时间:2024/06/11 17:04
2016.09.10


1.问题描述


今天做用户注册页面时,需要验证用户名,手机号和密码,当全部验证通过时才让disable状态的注册按钮可以点击。当正则验证格式正确时需要将用户名和手机号用ajax传递至后台进行查库验证是否重复,不重复时才验证通过。为了实现逻辑给三个输入框定义一个状态对象allowReg{'user_name':false,'user_tel':false,'user_password':false};
逻辑:
//验证输入并设置状态码
if(key正则验证通过){
$.ajax(
success: function(data) {
//查库验证通过,状态码设为true,否则设为false
                        if (data.status) {
                            allowReg[key] = true;
                        } else {
                            allowReg[key] = false;
                        }
console.log(allowReg);   ---位置2
                    },
);
}else{
allowReg[key] = false;
}
console.log(allowReg);  --- 位置2
//判断三个状态码都为true则点亮注册按钮,
if (allowReg['user_name'] && allowReg['user_tel'] && allowReg['user_password']) {
            $("#regist_btn").attr('disabled',false);
        }else{
            $("#regist_btn").attr('disabled',true);
        }

但是再测试时发现点亮的效果并不是预期,存在一个延迟,即此次输入验证通过,但是点亮按钮的判断条件却使用的上一次的验证结果。


2.解决过程


通过在 ajax的success函数最后 和 判断点亮按钮之前 加上console.log(allowReg)进行打印结果发现,两次打印的结果不一样,并且先执行 位置2 再执行 位置1.而且位置1输出的当前输入的验证结果,位置2输出的是上次输入的验证结果。
由此猜想可能是ajax的异步原因,上网查资料发现ajax默认使用异步请求,即先发送请求,但不等待返回结果,继续向下执行,当接收到返回结果后再执行success函数。所以以上逻辑会先发送请求,然后执行位置2,再判断是否点亮按钮,然后再执行success里面的设置状态码,所以就会先使用上次验证结果的状态码,然后再这只此次验证结果的状态码。

然后查询如何可以执行完ajax再向下执行,发现两种方法,1.判断是否点亮按钮的逻辑放在success函数里。2.使用ajax同步请求,即增加一个配置项 async:false,
由于user_password这个输入是不走后台验证的,只做正则验证,所以把逻辑放在success里的话会导致user_password正则验证通过的话不能及时点亮按钮,所以我使用了ajax的同步请求方式,通过测试发现问题解决,可以实现以上逻辑。


3.扩展


由于使用了ajax的同步请求方式,发现浏览器控制台报了一个警告:

jquery.js:9620   Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.

上网查询相关内容,发现这句话的意思是在主线程中使用了ajax同步请求,可能会造成主线程阻塞,从而影响用户体验。

因为如果使用了ajax同步请求,那么在请求返回之前,进程会一直处于阻塞状态,等待请求的返回,如果请求是在主线程中发起的,会造成整个浏览器处于阻塞状态。如果一直等不到请求返回结果,可能会导致页面卡死,就会影响用户体验。

然后发现大部分程序员和文档都提到要尽可能避免使用ajax同步请求,以避免这种情况出现。

在HTML5以前,JavaScript是完全的单线程方式,主线程之外不存在其他线程。但在HTML5中增加了Worker对象,每个Worker运行在一个独立的线程中,Worker线程被阻塞一般是不会影响主线程和浏览器的。因此,如果非要使用同步的Ajax(这种情况应该很少见),那就放到Worker线程中吧,千万千万不要放到主线程里。
(摘自网友 参考链接https://segmentfault.com/q/1010000002418129)

4.总结

看到ajax同步请求的弊端感觉后果还是很严重的,所以我这么做可能可能不太恰当,所以应该考虑将 判断逻辑放在success 里执行,至于user_password的判断可以通过将它也用ajax传递到后台进行一个简单验证,然后就可以实现都在success里进行判断。但是这样就增加了服务器的开销。








0 0