解决js ajax同步请求造成浏览器假死的问题


Posted in Javascript onJanuary 18, 2018

一、问题的起因

今天做一个需求遇到了这么个情况,就是用户个人中心有个功能,点击按钮,可以刷新用户当前的积分,这个肯定需要使用到ajax的同步请求了,当时喀喀喀三下五除二写玩了,大概代码如下:

/**
  * 异步当前用户积分 by zgw 20161216
  * @return {[type]} [description]
 */
 function flushIntegralSum() {

 //点击按钮刷新前修改按钮的文案,已经去掉点击事情,防止多次点击
  $("#flushbutton").replaceWith('<a style="color:#3fb0ff;font-size:14px;" href="javascript:void(0);" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" id="flushbutton">正在刷新</a>');
  $.ajax({
   url:'URL',
   type:'post',
   async:false,
   // data:{},
   success:function(json){
    json = eval('('+json+')');
    if(json.url){window.location.href=json.url;return;}
    $("#flushbutton").replaceWith('<a style="color:#3fb0ff;font-size:14px;" href="javascript:void(0);" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" onclick="flushFreeSum();" id="flushbutton">刷新积分</a>');
    if(json.code!=1){
     alert(json.msg);
    }else{
     $("#free_sum").html(json.free_sum);
    }
    return;
   }
  });
 }

本以为这么简单的功能喀喀喀随便写写就没事了,在运行的时候出现了问题,当用户点击刷新积分按钮时,文案没有修改为"正在刷新",但是ajax请求发送了,于是我查看网页代码,发现js其实把文案和html元素绑定的onclick事件去掉了,在请求成功后有变回原来的了,但是页面上边文案没有改变,当时很奇怪,不知道为什么html代码里边改变了,页面却没有变点变化

二、了解问题原因

问题的根源:当时我进行了排查,最后发现是 "async:false" 的问题,换成异步的就没有问题了,那为什么同步请求会产生代码失效的问题呢?

原因:浏览器的渲染(UI)线程和js线程是互斥的,在执行js耗时操作时,页面渲染会被阻塞掉。当我们执行异步ajax的时候没有问题,但当设置为同步请求时,其他的动作(ajax函数后面的代码,还有渲染线程)都会停止下来。即使我的DOM操作语句是在发起请求的前一句,这个同步请求也会“迅速”将UI线程阻塞,不给它执行的时间。这就是代码失效的原因。

三、解决问题

1.我当时使用了 setTimeout 来解决,把ajax代码放在sestTimeout中,让浏览器重启一个线程来操作,这样就解决问题了,代码如下:

function flushIntegralSum() {

 //点击按钮刷新前修改按钮的文案,已经去掉点击事情,防止多次点击
  $("#flushbutton").replaceWith('<a style="color:#3fb0ff;font-size:14px;" href="javascript:void(0);" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" id="flushbutton">正在刷新</a>');
  setTimeout(function(){
   $.ajax({
    url:'URL',
    type:'post',
    async:false,
    // data:{},
    success:function(json){
     json = eval('('+json+')');
     if(json.url){window.location.href=json.url;return;}
     $("#flushbutton").replaceWith('<a style="color:#3fb0ff;font-size:14px;" href="javascript:void(0);" rel="external nofollow" rel="external nofollow" rel="external nofollow" rel="external nofollow" onclick="flushFreeSum();" id="flushbutton">刷新积分</a>');
     if(json.code!=1){
      alert(json.msg);
     }else{
      $("#free_sum").html(json.free_sum);
     }
     return;
    }
   });
  },0) 
 }

setTimeout的第二个参数设为0,浏览器会在一个已设的最小时间后执行

到这里问题就解决了,但是你可以试试当你点击按钮的时候如果需要弹出一个gif图片,并且图片一直在旋转,提示更新中,你会发现图片虽然会显示,但是图片却是不动的,那是因为虽然同步请求延迟执行了,但是它执行期间还是会把UI线程给阻塞。这个阻塞相当牛逼,连gif图片都不动了,看起来像一张静态图片一样。结论很明显,setTimeout治标不治本,相当于把同步请求“稍稍”异步了一下,接下来还是会进入同步的噩梦,阻塞线程,这种方法只适合发请求之前操作简单的时间短的情况

2.使用 Deferred 来解决

以上这篇解决js ajax同步请求造成浏览器假死的问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js静态方法与实例方法分析
Jul 04 Javascript
无缝滚动js代码通俗易懂(自写)
Jun 19 Javascript
jQuery网页选项卡插件rTabs用法实例分析
Aug 26 Javascript
jQuery实现图片走马灯效果的原理分析
Jan 16 Javascript
node.js微信公众平台开发教程
Mar 04 Javascript
express文件上传中间件Multer详解
Oct 24 Javascript
详解angularjs结合pagination插件实现分页功能
Feb 10 Javascript
一种angular的方法级的缓存注解(装饰器)
Mar 13 Javascript
剖析Angular Component的源码示例
Mar 23 Javascript
angularJs自定义过滤器实现手机号信息隐藏的方法
Oct 08 Javascript
vue + any-touch实现一个iscroll 实现拖拽和滑动动画效果
Apr 08 Javascript
vue+springboot图片上传和显示的示例代码
Feb 14 Javascript
js实时监控文本框输入字数的实例代码
Jan 18 #Javascript
JavaScript实现删除数组重复元素的5种常用高效算法总结
Jan 18 #Javascript
react-router4 配合webpack require.ensure 实现异步加载的示例
Jan 18 #Javascript
分享ES6的7个实用技巧
Jan 18 #Javascript
vue 动态修改a标签的样式的方法
Jan 18 #Javascript
详解vue-meta如何让你更优雅的管理头部标签
Jan 18 #Javascript
Nuxt.js踩坑总结分享
Jan 18 #Javascript
You might like
文件上传类
2006/10/09 PHP
用php随机生成福彩双色球号码的2种方法
2013/02/04 PHP
PHP引用的调用方法分析
2016/04/25 PHP
php版微信公众号自定义分享内容实现方法
2016/09/22 PHP
基于Laravel实现的用户动态模块开发
2017/09/21 PHP
PHP大文件及断点续传下载实现代码
2020/08/18 PHP
个人总结的一些关于String、Function、Array的属性和用法
2007/01/10 Javascript
JS实现可改变列宽的table实例
2013/07/02 Javascript
基于jQuery的判断iPad、iPhone、Android是横屏还是竖屏的代码
2014/05/11 Javascript
使用phantomjs进行网页抓取的实现代码
2014/09/29 Javascript
基于JavaScript实现表单密码的隐藏和显示出来
2016/03/02 Javascript
微信小程序switch开关选择器使用详解
2018/01/31 Javascript
jquery 通过ajax请求获取后台数据显示在表格上的方法
2018/08/08 jQuery
vue动态设置img的src路径实例
2018/09/18 Javascript
AJAX在JQuery中的应用详解
2019/01/30 jQuery
layui固定下拉框的显示条数(有滚动条)的方法
2019/09/10 Javascript
Layui Form 自定义验证的实例代码
2019/09/14 Javascript
node.js实现http服务器与浏览器之间的内容缓存操作示例
2020/02/11 Javascript
Javascript生成器(Generator)的介绍与使用
2021/01/31 Javascript
Python中用Spark模块的使用教程
2015/04/13 Python
以一个投票程序的实例来讲解Python的Django框架使用
2016/02/18 Python
使用Python中的tkinter模块作图的方法
2017/02/07 Python
python一行sql太长折成多行并且有多个参数的方法
2018/07/19 Python
python3转换code128条形码的方法
2019/04/17 Python
如何解决cmd运行python提示不是内部命令
2020/07/01 Python
Python实现画图软件功能方法详解
2020/07/28 Python
PyQt实现计数器的方法示例
2021/01/18 Python
纯css3实现的竖形无限级导航
2014/12/10 HTML / CSS
工程业务员岗位职责
2013/12/31 职场文书
护士自我鉴定总结
2014/03/24 职场文书
加油口号大全
2014/06/13 职场文书
建筑院校毕业生求职信
2014/06/13 职场文书
先进班组材料范文
2014/12/25 职场文书
Pytest之测试命名规则的使用
2021/04/16 Python
VS2019连接MySQL数据库的过程及常见问题总结
2021/11/27 MySQL
Mysql外键约束的创建与删除的使用
2022/03/03 MySQL