最近工作时发现一个产品中的localStorage在IE下出现了问题。
Bug Details:
在IE下,多开几个页面,有的页面能同步到数据,有的页面不能同步。手工查看本地存储,发现本地存储的确在各个页面是不同的,而且奇妙的是,再打开新的页面时,不一定是什么情况,也就是说每个页面的本地存储不一定是哪种数据,有的和之前某个页面相同,有的可能是一种完全不同的数据。
幸运的事情却发生了。在经过了一段时间的检查之后,我还是不得其解,于是开始思考可能是哪里出现问题(我发现问题解决不了的时候仔细想想或许就能理清头绪)。过了一段时间之后,发现有些没有同步的页面居然同步了。因为本地存储是在一个iframe中,我单独检查了这个iframe的同步情况,它的同步没有任何问题。难道是因为主页面的运算量太大了,导致了它们没有同步到?因为此时我已经开始推测IE的localStorage的结构了,初步怀疑是localStorage是存储在硬盘上或者哪里的内存然后再同步到硬盘上,总之是在硬盘上,然后各个页面保持了一份localStorage在各自的内存里,各个页面定时地同步或者是一个主程序主动地推送到各个页面。那么如果运算量太大应该会导致同步不上吧。
于是我在本地搞了一个页面执行大量的运算,然后同时取localStorage.length,通过增加localStorage的条目来看各个页面是不是同步了起来。不过结论是,大量运算会有影响,但是到足以影响页面在那么长时间不能同步,页面也已经差不多不能动了。
之后,我觉定还是是不是之前的某次的任务导致了这个悲剧。从之前一个提交的版本开始二分,因为那个版本是我亲自测试过OK已经上线的。
Test Steps:
关闭所有页面,并打开3个也上页面,待页面稳定时,从ff发送消息,观察每个页面是否都同步到。
2-24 r***** Fail confirm 2-15 r***** OK
锁定到某个版本。
Conclusion:
于是结论是,2-24日的提交的版本导致了这个问题。事情是这样的:
在这个版本中的功能中,会绑定全局事件,每1秒响应一次mousemove,focus,click,keydown这4个事件,之后的某次改动中将1秒这个限制注释掉了。 导致的问题是,每次上述4种事件一触发就要去写本地存储,而mousemove事件是很多的, 推测,这个时候,会导致一个很长的写本地存储的队列,而对于其他页面,则要在很久之后(视事件触发多少而定)才能同步到。 于是就造成了这样的现象:等待一段时间之后,又能同步到消息。
Expand:
之后的问题是,得出一些有益的结论。大概知道了问题所在,来一个测试好了。建立一个页面,绑定了全局的mousemove,focus,click,keydown事件,保存事件触发时的时间,然后定时取出这个时间和LocalStorage.length。
打开多个窗口,在一个窗口中移动鼠标,会现其他页面开始时还可以同步到,但是很快就不行了,把鼠标移出窗口,等待一段时间之后,可以发现,其他页面又同步到了。于是,问题就是。目前我的机器1s会响应180次左右的mousemove事件。另外我又测试了keydown事件,1s会响应二三十次的样子,IE9对这个频率还是很轻松的。
最后关于localStorage read的效率,我认为这个应该是内存的读取速度,因为每个页面所保存LocalStorage是同步来的。
测试的页面代码:
Time:
LocalStorage Length: