先上Demo,有兴趣的可以先试一下:
http://www.zeakhold.com/crash/
(温馨提示:访问前请保存好浏览器其他窗口的任务,整人被打概不负责嘿嘿~)
事情还是得从 IT Security Tweets ™ 的一篇推文说起:
也就是说,这段 javascript 代码,能让浏览器崩溃并且能让iPhone重启?!
于是打开电脑跃跃欲试,当满怀好奇地在浏览器上执行了这段代码后发现: Chrome 立马陷入了卡死的状态,更要命的是点击关闭窗口没响应!!
打开任务管理器,发现CPU已飙升至100%:
立马停掉 Chrome ,还好一切恢复正常。
不过也纳闷着,这几行代码究竟又是什么梗?
<script> var total = ""; for (var i = 0; i < 1000000; i++) { total = total + i.toString(); history.pushState(0, 0, total); } </script>
从代码看应该是history对象的pushState()方法在1000000次的循环中耗尽了系统的资源。看了一下相关的博客介绍,才发现原来pushState()是HTML5引进的新特性之一,它的引进与Ajax有着密切的关系。
我们知道,Ajax的出现方便了用户浏览网页,它允许用户在不用刷新的情况下更新网站的内容,但是这样也引发了一个问题,就是更新网站内容之后,不同的页面之间还是有区别的,而这种区别无法体现在URL上:Ajax产生的页面变化并没有伴随着URL的改变,当前页的URL仍与前一页的URL一样,这就导致我们无法通过前进、后退来切换页面。在传统的浏览体验中,页面内容的改变往往会伴随着URL的改变,而这些改变对应着“前进”和“后退”,但是Ajax的出现破坏了这种独特的体验。为此,HTML5 给history对象新增了一些特性来解决这个问题,其中就包括上面代码里的pushState()方法。
根据W3C的HTML5文档,pushState()方法的作用是在浏览器的历史记录栈里面添加记录(Pushes the given data onto the session history),该方法包含三个参数:一个事件对象,一个加进历史记录的页面的标题(通常被浏览器忽略),一个加进历史记录的地址。这样一来,当Aja作做变更一次,就可以用pushState()方法添加一次历史记录,在此基础上再加上其它几个方法,便使得我们可以主动地对历史记录进行编辑,无刷新改变URL,从而弥补了使用Ajax带来的这个缺陷。
回到代码,for做了1000000次循环,浏览器的历史记录(压入URL)也就修改了1000000次,并且,每次循环的URL都在上一次的基础叠加,这样不断循环下去向history添加记录,迅速地消耗系统内存资源,从而导致浏览器的崩溃。
了解缘由后,选了几个手机设备做了测试,虽然没有出现twitter所说的能让iPhone设备重启的现象,但是都不约而同地搞挂了浏览器:
iPhone 6s(Safari) —— 直接闪出苹果图标,3秒后回到主界面,恢复正常(这个不算重启吧);
iPhone 4(Safari) —— 卡死在浏览器界面,强制关闭浏览器后恢复正常;
华为 P6 (内置浏览器) ——卡死在浏览器界面,强制关闭浏览器后恢复正常;
魅族 MX3 (内置浏览器、UC浏览器) —— 卡死在浏览器界面,强制关闭浏览器后恢复正常;
QQ、微信里也试了一下打开那个页面,结果都是闪退到聊天主界面。
有了这段代码后,似乎又多了许多整蛊小伙伴的新姿势嘿嘿~
(转载请注明出处——http://www.cnblogs.com/zeakhold/)