Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

在bom/engine.md中对setInterval解释有误 #39

Closed
oe opened this issue Jul 24, 2014 · 9 comments
Closed

在bom/engine.md中对setInterval解释有误 #39

oe opened this issue Jul 24, 2014 · 9 comments

Comments

@oe
Copy link

oe commented Jul 24, 2014

章节4.5运行队列有如下代码

setInterval(function(){console.log(2);},1000);
(function (){ sleeping(3000);})();

其执行结果并不是在sleep后立刻输出三个2, 而是只有 一个 2.

setInterval并不会将同一个任务累积, setInterval会周期性的尝试向队列添加任务, 当检测到任务已经在队列中的时候, setInterval便会跳过, 不会出现一个任务同时多次出现在队列中的情况.

使用以下片段可以更好理解, 等待几秒钟后关闭alert即可看到结果.

var count = 1;
setInterval(function () {
  console.log(count++);
}, 1000);
alert('Started!');

个人以为使用时间轴图表的方式可以将其描述的更加明晰. 由于个人表达能力有限, 故未直接修改markdown.

@ghost
Copy link

ghost commented Jul 24, 2014

alert 帶阻塞頁面內容運行的特殊效果,我認爲該例子不妥。另外,你的推測也不夠嚴格,假如不能累積同一任務,setInterval 又怎能實現?

@oe
Copy link
Author

oe commented Jul 24, 2014

如果用alert 不太好的话, 可以使用以下代码片段来达到延时的效果:

function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}

setInterval 还是会周期性的调用, 但是如果任务已经在队列中那它就不会将该任务添加至队列中.

@oe
Copy link
Author

oe commented Jul 24, 2014

在浏览器中, JS就是单线程, 如果js执行耗时太长, 就会导致UI无响应, 即假死. 将我贴出来的代码执行下就可以看到效果了.

@ghost
Copy link

ghost commented Jul 24, 2014

嗯,我应该理解你的意思了。就是单线程,连 setInterval 的內部操作也难逃一劫。

稍微改了一下 sleep 函数,另外用 setTimeout 来竞赛感觉好一些:

function sleep(milliseconds) {
  var start = new Date().getTime();
  while (true) {
    if ((new Date()).getTime() - start > milliseconds){
      break;
    }
  }
  console.log('Wake up!');
}

var i = 0;
setTimeout(function () {
  sleep(3000);
}, 1000);
setInterval(function(){console.log(i++);},2000);

才想起这不在 ECMAScript 的标准内,也不知道阮先生是用什么浏览器测试的啊,至少我在新版 Chrome 和 Firefox 上的测试结果如你所述。

@ghost
Copy link

ghost commented Jul 24, 2014

不过我认为这是单线程引起的,而不是 setInterval 会检测是否存在重复任务。

@oe
Copy link
Author

oe commented Jul 24, 2014

IE8上表现也如此. 嗯, 说是单线程引起的也可以解释.  setInterval 和setTimeout会使用CPU时钟, 浏览器可能需要做特殊处理, 不清楚底层是否有检查, 但是看到很多博客上多大如此解释.

@ghost
Copy link

ghost commented Jul 24, 2014

唔,的确两种解释都可能。interval id 可能是关联在 hash 表上方便迅速了解任务是否结束的吧。单线程的应该只是执行流程,而不包括定时器,否则连定时器也约束自己,要得多麻烦啊……

@ghost
Copy link

ghost commented Jul 24, 2014

所以文中的例子应该改成类似这样的,分开两个独立的任务,就可以观察到拥塞的奇怪结果了:

var i = 1, j = -1;
setTimeout(function () {
  sleep(3000);
}, 1000);
setInterval(function(){console.log(i++);},2000);
setInterval(function(){console.log(j--);},2000);

@oe
Copy link
Author

oe commented Jul 24, 2014

嗯. 刚看到一篇博文定时器有详细解释, 英文页面 Understanding timers: setTimeout and setInterval.

还有个小问题是举例中好多定时器设定的时间都小于16ms, 实际上大多浏览器对于小于16ms的时间都当做16ms处理, chrome特别一点可以支持更小的时间间隔(chrome的计时精度较高, 所以最近就爆出chrome很耗电的bug).

@ruanyf ruanyf closed this as completed Jan 24, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants