为什么尽量别用 setInterval? 下面本篇文章就来浅谈一下尽量别用 setInterval 的原因. 有一定的参考价值, 有需要的朋友可以参考一下, 希望对大家有所帮助.
在开发一个在线聊天工具时, 经常会有过多少毫秒就重复执行一次某操作的需求."没问题", 大家都说,"用 setInterval 好了." 我觉得这个点子很糟糕.
原因之一: setInterval 无视代码错误
setInterval 有个讨厌的习惯, 即对自己调用的代码是否报错这件事漠不关心. 换句话说, 如果 setInterval 执行的代码由于某种原因出了错, 它还会持续不断 (不管不顾) 地调用该代码. 看代码
- function a() {
- try{
- a.error.here;
- } catch(e){
- $('body').append('<div>' + e.toString() + '</div>');
- throw e;
- }
- }
- function b() {
- try{
- b.error.here;
- } catch(e)
- {
- $('body').append('<div>' + e.toString() + '</div>');
- throw e;
- }
- setTimeout(b, 2000);
- }
- setInterval(a, 2000);
- setTimeout(b, 2000);
原因之二: setInterval 无视网络延迟
假设你每隔一段时间就通过 Ajax 轮询一次服务器, 看看有没有新数据(注意: 如果你真的这么做了, 那恐怕你做错了; 建议使用 "补偿性轮询"(backoff polling)[1]). 而由于某些原因(服务器过载, 临时断网, 流量剧增, 用户带宽受限, 等等), 你的请求要花的时间远比你想象的要长. 但 setInterval 不在乎. 它仍然会按定时持续不断地触发请求, 最终你的客户端网络队列会塞满 Ajax 调用. 看代码
- var n = 0,
- t = 0,
- u = 0,
- i, s = 'Stopping after 25 requests, to avoid killing jsfiddle's server';
- function a() {
- $.post('/ajax_html_echo/', function () {
- --n;
- });
- ++n;
- ++t;
- $('#reqs').HTML(n + 'a() requests in progress!');
- if (t> 25) {
- clearInterval(i);
- $('#reqs').HTML(s);
- }
- }
- function b() {
- ++u;
- $.post('/ajax_html_echo/', function () {
- $('#req2').HTML('b():' + new Date().toString());
- if (u <= 25) {
- setTimeout(b, 500);
- } else {
- $('#req2').HTML(s);
- }
- });
- }
- i = setInterval(a, 500);
- setTimeout(b, 500);
原因之三: setInterval 不保证执行
与 setTimeout 不同, 你并不能保证到了时间间隔, 代码就准能执行. 如果你调用的函数需要花很长时间才能完成, 那某些调用会被直接忽略. 看代码
- function slow() {
- $.Ajax({
- url: '/echo/html/',
- async: false,
- data: {
- delay: 1
- },
- complete: function () {
- }
- });
- $('#reqs').text(~~((new Date() - start) / 100) + 'expected,' + iters + 'actual');
- if (iters++> 4) {
- $('#reqs').append('<br>Stopping after 5 iterations');
- clearInterval(iv);
- }
- };
- var iv = setInterval(slow, 100), start = +new Date(), iters = 0;
解决之道很简单: 用 setTimeout
与其使用 setInterval, 不如在适当的时刻通过 setTimeout 来调用函数自身. 在前面两个示例中, 使用 setInterval 的函数 a 都出错了, 而使用 setTimeout 的函数 b 则表现很好.
如果必须保证间隔相等怎么办?
如果确实要保证事件 "匀速" 被触发, 那可以用希望的延迟减去上次调用所花时间, 然后将得到的差值作为延迟动态指定给 setTimeout. 不过, 要注意的是 JavaScript 的计时器并不是非常精确[2]. 因此你不可能得到绝对 "平均" 的延迟, 即使使用 setInterval 也不行, 原因很多(比如垃圾回收, JavaScript 是单线程的, 等等). 此外, 当前浏览器也会将最小的超时时间固定在 4ms 到 15ms 之间. 因此不要指望一点误差也没有.
文中链接
- http://github.com/blog/467-smart-js-polling
- http://ejohn.org/blog/accuracy-of-javascript-time/
更多前端开发 https://www.html.cn/ 知识, 请查阅 HTML 中文网 !!
来源: http://www.css88.com/web/javascript/17426.html