http://www.nowamagic.net/librarys/veda/detail/787  

在Web开发的时候经常会遇到浏览器不响应事件进入假死状态,甚至弹出“脚本运行时间过长“的提示框,如果出现这种情况说明你的脚本已经失控了,必须进行优化。

为什么会出现这种情况呢,我们先来看一下浏览器的内核处理方式:

浏览器的内核是多线程的,它们在内核制控下相互配合以保持同步,一个浏览器至少实现三个常驻线程:javascript引擎线程,GUI渲染线程,浏览器事件触发线程。

  1. JavaScript引擎是基于事件驱动单线程执行的,JS引擎一直等待着任务队列中任务的到来然后加以处理,浏览器无论再什么时候都只有一个JS线程在运行JS程序。
  2. GUI 渲染线程负责渲染浏览器界面,当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行。但需要注意 GUI渲染线程与JS引擎是互斥的,当JS引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。
  3. 事件触发线程,当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理。这些事件可来自JavaScript引擎当前执行的代码块如setTimeOut、也可来自浏览器内核的其他线程如鼠标点击、AJAX异步请求等,但由于JS的单线程关系所有这些事件都得排队等待JS引擎处理。

了解了浏览器的内核处理方式就不难理解浏览器为什么会进入假死状态了,当一段JS脚本长时间占用着处理机就会挂起浏览器的GUI更新,而后面的事件响应也被排在队列中得不到处理,从而造成了浏览器被锁定进入假死状态。另外JS脚本中进行了DOM操作,一旦JS调用结束就会马上进行一次GUI渲染,然后才开始执行下一个任务,所以JS中大量的DOM操作也会导致事件响应缓慢甚至真正卡死浏览器,如在IE6下一次插入大量的HTML。而如果真的弹出了“脚本运行时间过长“的提示框则说明你的JS脚本肯定有死循环或者进行过深的递归操作了。

Nicholas C. Zakas认为不论什么脚本,在任何时间、任何浏览器上执行都不应该超过100毫秒,否则一定要将脚本分解成若干更小的代码段。那么我们该如何来做呢:

第一步,优化你的循环,循环体中包含太多的操作和循环的次数过多都会导致循环执行时间过长,并直接导致锁死浏览器。如果循环之后没有其他操作,每次循环只处理一个数值,而且不依赖于上一次循环的结果则可以对循环进行拆解,看下面的chunk的函数:

function chunk(array, process, context) {setTimeout(function() {var item = array.shift();process.call(context, item);if (array.length > 0) {setTimeout(arguments.callee, 100);}), 100);
}

chunk()函数的用途就是将一个数组分成小块处理,它接受三个参数:要处理的数组,处理函数以及可选的上下文环境。每次函数都会将数组中第一个对象取出交给process函数处理,如果数组中还有对象没有被处理则启动下一个timer,直到数组处理完。这样可保证脚本不会长时间占用处理机,使浏览器出一个高响应的流畅状态。

其实在我看来,借助JS强大的闭包机制任何循环都是可拆分的,下面的版本增加了callback机制,使可再循环处理完毕之后进行其他的操作。

function chunk(array,process,cbfun){var i=0,len = array.length;    //这里要注意在执行过程中数组最好是不变的setTimeout(function(){process( array[i] , i++ );    //循环体要做的操作if( i < len ){setTimeout(arguments.callee,100)}else{cbfun()                //循环结束之后要做的操作}}
}

第二步,优化你的函数,如果函数体内有太多不相干但又要一起执行的操作则可以进行拆分,考虑下面的函数:

function dosomething(){dosomething1();dosomething2();
}

dosomething1和dosomething2互不相干,执行没有先后次序,可用前面提到的chunk函数进行拆分:

function dosomething(){chunk([dosomething1,dosomething2],function(item){item();})
}

或者直接交给浏览器去调度

function dosome(){setTimeout(dosomething1,0);setTimeout(dosomething2,0);
}

第三步,优化递归操作,函数递归虽然简单直接但是过深的递归操作不但影响性能而且稍不注意就会导致浏览器弹出脚本失控对话框,必须小心处理。

看以下斐波那契数列的递归算法:

function fibonacci(n) {return n < 2 ? n: fibonacci(n - 1) + fibonacci(n - 2);
};

fibonacci(40)这条语句将重复调用自身331160280次,在浏览器中执行必然导致脚本失控,而采用下面的算法则只需要调用40次

fibonacci = function(n){var memo = {0:0,1:0};         //计算结果缓存var shell = function(n){var result = memo[n];if( typeof result != 'number' )    //如果值没有被计算则进行计算memo[n] = shell(n-1) + shell(n -2)return memo[n];}return shell(n);
}

这项技术被称为memoization,他的原理很简单就是同样的结果你没必要计算两次。另一种消除递归的办法就是利用迭代,递归和迭代经常会被作为互相弥补的方法。

第四步,减少DOM操作,DOM操作的代价是相当昂贵的,大多数DOM操作都会触发浏览器的回流(reflow)操作。例如添加删除节点,修改元素样式,获取需要经过计算的元素样式等。我们要做的就是尽量少的触发回流操作。

el.style.width = '300px' el.style.height = '300px' el.style.backgroundColor = 'red'

上面的操作会触发浏览器的三次回流操作,再看下面的方式:

el.className = 'newStyle'

通过设置改元素的className一次设置多个样式属性,将样式写再CSS文件中,只触发一次回流,达到了同样是效果而且效率更高。因为浏览器最擅长的就是根据class设置样式。

还有很多可以减少DOM操作的方法,在此就不多说了,但是一个基本的原则就是让浏览器去做它自己擅长的事情,例如通过class来改变元素的属性。

相信经过上面的优化的过程必定可以大大提高用户体验,不会出现浏览器被锁死和弹出脚本失控的对话框,使你的浏览器从繁重的任务中解放出来。需要指出的是上面这些优化并不是必须的,只有当一段脚本的执行时间真的影响到了用户体验才需要进行。虽然它们让用户觉得脚本的执行变快了,但其实完成同一个操作的时间可能被延长了,这些技术只是让浏览器处于一个快速响应的状态,使用户浏览更流畅。

最后送一句忠告:过早优化是万恶之源。

我喜欢
我的收藏夹

不打个分吗?

  • 20
  • 40
  • 60
  • 80
  • 100

转载随意,但请带上本文地址:

http://www.nowamagic.net/librarys/veda/detail/787

转载于:https://www.cnblogs.com/amws/p/3347225.html

优化js设计,防止浏览器假死(转)相关推荐

  1. 转:优化js脚本设计,防止浏览器假死

    原链接打不开了,复制一份保存: 在Web开发的时候经常会遇到浏览器不响应事件进入假死状态,甚至弹出"脚本运行时间过长"的提示框,如果出现这种情况说明你的脚本已经失控了,必须进行优化 ...

  2. js样式会影响ajax,js ajax同步请求造成浏览器假死的问题

    今天写了一个简单的loading效果,希望在点击加载按钮后会出现loading字样,然后执行ajax同步请求,加载完之后loading样式消失,本来是很简单的需求,结果遇上了很尴尬的问题~ 问题:当我 ...

  3. setTimeout 导致的浏览器假死

    setTimeout 导致的浏览器假死 问题   前几天,同事遇到一个浏览器假死的问题.就是浏览器在响应一个请求的时候,就突然不响应时间,进入假死状态,Cup也飙升到100%. 但是这个问题只出现在I ...

  4. js防止刷访问量_优化js脚本设计,防止浏览器假死

    在Web开发的时候经常会遇到浏览器不响应事件进入假死状态,甚至弹出"脚本运行时间过长"的提示框,如果出现这种情况说明你的脚本已经失控了,必须进行优化. 为什么会出现这种情况呢,我们 ...

  5. 浏览器假死,浏览器堵塞,浏览器卡的原因

    在Web开发的时候经常会遇到浏览器不响应事件进入假死状态,甚至弹出"脚本运行时间过长"的提示框,如果出现这种情况说明你的脚本已经失控了. 一个浏览器至少存在三个线程:js引擎线程( ...

  6. ajax异步超时,AjaxPro实现异步调用,解决浏览器假死及超时问题(示例代码)

    平时使用AjaxPro的时候基本上非常easy var msg = UseClass.Method(argument).value; 由于后台响应比較慢,所以加了个"loading" ...

  7. 网站是怎么了,一直http/1.1 302 found 浏览器假死了一样

    网站不知道是怎么了,是程序的问题?还是服务器的问题?还是htaccess配置文件的问题? 反正设置了404  ErrorDocument,结果,大部分时候,请求到了404页面,浏览器就一直加载加载,反 ...

  8. 关于vs2008设计视图假死的原因及解决方案总结

    前些天从微软官网(中国)下载了vs2008的90天试用版,安装很顺利.但使用时发现,从源视图向设计视图切换时,界面出现了假死现象,重装后亦无效.我从网上搜索原因,发现很多朋友都有类似的问题,但解决方案 ...

  9. 浏览器真的能“永不假死”?——六款主流浏览器防假死功能测试

    作者:一石来源:家用电脑 浏览器是大家上网必备的工具,而浏览器假死也是大家在上网时常常所遇到的问题,让人头疼.最近各款主流浏览器纷纷推出了最新版本,我们可以发现一个相同点就是他们都以"防假死 ...

最新文章

  1. 多篇开源CVPR 2020 语义分割论文
  2. python爬虫之selenium,谷歌无头浏览器
  3. Linux stat命令显示文件的状态信息
  4. IDEA中Git操作
  5. kafka+zookeeper安装配置
  6. java没通过测试_我们应该把没有通过测试的故事回退到“开发”状态吗
  7. Python标准库random用法精要
  8. 路由交换基础——DHCP工作原理及DHCP Relay
  9. 静默安装apk,静默卸载apk
  10. [Linux程序设计][调试][splint]
  11. 【学习笔记】堆的定义及其建立、排序等基本操作的实现
  12. 简单的网页编辑器js代码
  13. excel常用函数汇总 Excel公式大全 excel函数应用500例
  14. 怎么重置计算机网络设置密码,怎么重新设置wifi密码_如何重新设置无线密码?-192路由网...
  15. 华为笔试题-圣诞的祝福
  16. 倒计时21天,房贷利率新政要来了,有银行已率先公布报价
  17. B站最全Redis教程全集(2021最新版)(图灵学院诸葛)学习笔记一--五种数据结构与应用场景
  18. 【Java开发】设计模式 19:观察者模式
  19. 2021年中国日用玻璃生产现状及竞争格局分析,行业朝“五化”方向发展「图」
  20. GBase 8d证书查看

热门文章

  1. Java 集合-取最大/最小值
  2. BERT 预训练学习(数据:样本构建、输入格式;算法:transformer、mlm和nsp任务)
  3. 3.Java获得内网网段所有可通信的ip地址
  4. 关于excel表格刷新问题
  5. php云4.5旗舰版,PHPYun 5.0
  6. 这六本第四届橙瓜网络文学奖评分杀入前十的作品你一定没看过!
  7. 输出,求和,高斯求和
  8. java:用程序输出二元一次方程的反函数
  9. kafka Java客户端之Connect API
  10. vector的简单介绍