setTimeout(callback, 进入主线程的时间)所以什么时候可以执行 callback,需要看 主线程前面还有多少任务待执行。由此,才有了这个问题。我们可以通过这个场景来进行演示:
functiontimer() { var speed = 50, // 设定间隔 counter = 1, // 计数 start = new Date().getTime(); functioninstance() { var ideal = (counter * speed), real = (new Date().getTime() - start); // 堆代码 duidaima.com counter++; form.ideal.value = ideal; // 记录理想值 form.real.value = real; // 记录真实值 var diff = (real - ideal); form.diff.value = diff; // 差值 window.setTimeout(function() { instance(); }, speed); }; window.setTimeout(function() { instance(); }, speed); } timer();而我们如果在 setTimeout 还未执行期间加入一些额外的代码逻辑,再来看看这个差值。
... window.setTimeout(function() { instance(); }, speed); for(var x=1, i=0; i<10000000; i++) { x *= (i + 1); } } ...
// 模拟代码 function setTimeout2 (cb, delay) { let startTime = Date.now() loop() functionloop () { const now = Date.now() if (now - startTime >= delay) { cb(); return; } requestAnimationFrame(loop) } }
... window.setInterval2(function () { instance(); }, speed); } for (var x = 1, i = 0; i < 10000000; i++) { x *= (i + 1); } ...
function timer(time) { const startTime = Date.now(); while(true) { const now = Date.now(); if(now - startTime >= time) { console.log('误差', now - startTime - time); return; } } } timer(5000);打印:误差 0
显然这样的方式很精确,但是我们知道 js 是单线程运行,使用这样的方式强行霸占线程会使得页面进入卡死状态,这样的结果显然是不合适的。
functiontimer() { var speed = 500, counter = 1, start = new Date().getTime(); functioninstance() { var real = (counter * speed), ideal = (new Date().getTime() - start); counter++; var diff = (ideal - real); form.diff.value = diff; window.setTimeout(function() { instance(); }, (speed - diff)); // 通过系统时间进行修复 }; window.setTimeout(function() { instance(); }, speed); }