Javascript setTimeout过早调用函数

Javascript setTimeout过早调用函数,javascript,node.js,settimeout,Javascript,Node.js,Settimeout,我的库中有基于实时的测试用例,我注意到测试将随机失败,出现1毫秒的错误: expect(已接收)。toBeGreaterThanOrEqual(已接收) 预期:>=1000 收到:999 这似乎是由于setTimeout过早调用函数造成的 所以我写了一个单独的测试脚本: let last=Date.now() 设置超时(下一步,1000) 函数next(){ if(Date.now()-lastrealOrigSetTimeout(func,ms-Math.random(),…args); 常

我的库中有基于实时的测试用例,我注意到测试将随机失败,出现1毫秒的错误:

expect(已接收)。toBeGreaterThanOrEqual(已接收)
预期:>=1000
收到:999
这似乎是由于setTimeout过早调用函数造成的

所以我写了一个单独的测试脚本:

let last=Date.now()
设置超时(下一步,1000)
函数next(){
if(Date.now()-last<1000)进程退出(1)
last=日期。现在()
设置超时(下一步,1000)
}
在Node.js v12.19.0、v14.15.3、v15.4.0上,它将随机失败:有时脚本可以继续运行,有时脚本将很快退出。 这不仅发生在我的本地计算机上,也发生在Github的CI服务器上

我的问题:这是一个bug吗?或者setTimeout的某种预期行为?或者
Date.now()

更新:另请参见

UPDATE:using
git bisect
罪魁祸首如下: 这似乎是一个bug,而不是预期的行为。我会投票反对总是添加1ms,因为行为不一致。(但是,它是否会早于1毫秒?我观察的时间不超过1毫秒)您可以通过以下方法解决此问题:

const origSetTimeout = setTimeout;
setTimeout = (f, ms, ...args) => {
  let o;
  const when = Date.now() + ms,
    check = ()=> {
      let t = when - Date.now();
      if (t > 0) Object.assign(o, origSetTimeout(check, t));
      else f(...args);
    };
  return o = origSetTimeout(check, ms);
};
它将允许
clearTimeout()
,即使在解决问题时也是如此

下面是一个浏览器代码,它模拟问题并每3秒交替解决:

//模拟问题
const realOrigSetTimeout=setTimeout;
setTimeout=(func,ms,…args)=>realOrigSetTimeout(func,ms-Math.random(),…args);
常数ms=200;
让when=Date.now()+ms;
设置超时(下一个,毫秒);
函数next(){
让现在=Date.now();
设置超时(下一个,毫秒);
log(现在{
让我们一起来;
const when=Date.now()+ms,
检查=()=>{
设t=when-Date.now();
如果(t>0)Object.assign(o,origSetTimeout(check,t));
else f(…args);
};
返回o=初始设置超时(检查,毫秒);
};
setTimeout(U8;=>{
console.log(“删除解决方法”);
setTimeout=origSetTimeout;
setTimeout(解决方案,3000);
}, 3000);
}

setTimeout(解决方案,3000)setTimeOut参数的延迟从来不是一个计时函数,它只告诉系统何时返回函数。此延迟取决于其他处理器任务,并且从未处于特定的时间time@MisterJojo我知道,我理解为什么延迟1000可能变成1000+,但1000变成999…这真的正常吗?是的,这是“正常”这是一个tolerance@MisterJojo这让我很困惑,Node.js的文档似乎有所不同:“唯一的保证是超时不会比声明的超时时间间隔更早执行。”另外,看看这里,也许它会让您了解为什么会在您的系统上发生这种情况
const origSetTimeout = setTimeout;
setTimeout = (f, ms, ...args) => {
  let o;
  const when = Date.now() + ms,
    check = ()=> {
      let t = when - Date.now();
      if (t > 0) Object.assign(o, origSetTimeout(check, t));
      else f(...args);
    };
  return o = origSetTimeout(check, ms);
};