解决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 相关文章推荐
浅谈Javascript面向对象编程
Nov 15 Javascript
jquery uploadify 在FF下无效的解决办法
Sep 26 Javascript
node.js中的fs.closeSync方法使用说明
Dec 17 Javascript
JavaScript 学习笔记之基础中的基础
Jan 13 Javascript
基于jQuery实现歌词滚动版音乐播放器的代码
Sep 17 Javascript
深入理解JavaScript中的块级作用域、私有变量与模块模式
Oct 31 Javascript
微信公众号支付H5调用支付解析
Nov 04 Javascript
利用transition实现文字上下抖动的效果
Jan 21 Javascript
jQuery实现复制到粘贴板功能
Feb 11 Javascript
通过构造函数实例化对象的方法
Jun 28 Javascript
es6中let和const的使用方法详解
Feb 24 Javascript
vue自定义指令和动态路由实现权限控制
Aug 28 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
PHP函数之error_reporting(E_ALL ^ E_NOTICE)详细说明
2011/07/01 PHP
基于PHP+Ajax实现表单验证的详解
2013/06/25 PHP
PHP实用函数分享之去除多余的0
2015/02/06 PHP
thinkPHP简单遍历数组方法分析
2016/05/16 PHP
精心挑选的12款优秀的基于jQuery的手风琴效果插件和教程
2012/08/22 Javascript
前台js对象在后台转化java对象的问题探讨
2013/12/20 Javascript
邮箱下拉自动填充选择示例代码附图
2014/04/03 Javascript
node.js中的fs.writeFile方法使用说明
2014/12/14 Javascript
js+html5实现canvas绘制简单矩形的方法
2015/06/05 Javascript
把Node.js程序加入服务实现随机启动
2015/06/25 Javascript
JS实现网页Div层Clone拖拽效果
2015/09/26 Javascript
轻松学习jQuery插件EasyUI EasyUI创建CRUD应用
2015/11/30 Javascript
javascript对浅拷贝和深拷贝的详解
2016/10/14 Javascript
AngularJS学习笔记(三)数据双向绑定的简单实例
2016/11/08 Javascript
jQuery为某个div加入行样式
2017/06/09 jQuery
微信小程序实现折叠与展开文章功能
2018/06/12 Javascript
JavaScript设计模式之工厂模式简单实例教程
2018/07/03 Javascript
微信小程序select下拉框实现效果
2019/05/15 Javascript
Vue常用的全选/反选的示例代码
2020/02/19 Javascript
Vue中使用better-scroll实现轮播图组件
2020/03/07 Javascript
Python 开发Activex组件方法
2009/11/08 Python
详解Python发送邮件实例
2016/01/10 Python
python逆序打印各位数字的方法
2018/06/25 Python
Tornado Web Server框架编写简易Python服务器
2018/07/28 Python
pandas数据处理进阶详解
2019/10/11 Python
SteelSeries赛睿官网:游戏外设和配件的领先制造商(耳机、键盘、鼠标和鼠标垫)
2018/06/17 全球购物
会计专业大学生职业生涯规划书
2014/02/11 职场文书
人事专员的职责
2014/02/26 职场文书
遗体告别仪式主持词
2014/03/20 职场文书
作风建设整改方案
2014/10/27 职场文书
2015年人力资源部工作总结
2015/04/30 职场文书
2019关于实习生工作安排及待遇的管理方案!
2019/07/16 职场文书
nginx常用命令放入shell脚本详解
2021/03/31 Servers
Vue中插槽slot的使用方法与应用场景详析
2021/06/08 Vue.js
海弦WR-800F
2022/04/05 无线电
向Spring IOC 容器动态注册bean实现方式
2022/07/15 Java/Android