⚡ 30 秒速记
- 定时器到期只代表获得后续调度资格
- 当前任务和微任务可能继续推迟回调
- 深层嵌套有最小延迟,后台还可能被节流
- 对象方法单独传入会丢失原接收者
- 倒计时按目标时间计算,不靠次数累减
setTimeout 是预约稍后执行,不是预约一个绝对准点的时刻。 延迟满足后,回调仍要等事件循环调度,主线程长任务和微任务堆积都会让它晚到。浏览器还会对嵌套或后台定时器采取限制,具体节流策略不能写成所有环境统一的固定值。做倒计时要用目标时间减当前时间,组件退出时则清理定时器,避免失效回调继续改状态。
版本校准: 原理文章中的代码代表特定实现与写作时间。应用到当前项目时,应先确认浏览器、框架或工具的主版本,再区分稳定的规范语义、可变化的内部实现和项目自身约束。
setTimeout,它就是一个定时器,用来指定某个函数在多少毫秒之后执行
# setTimeout用法
var timeoutID = setTimeout(function[, delay, arg1, arg2, ...]);
var timeoutID = setTimeout(function[, delay]);
var timeoutID = setTimeout(code[, delay]);
- 第一个参数为函数或可执行的字符串(比如
alert('test'),此法不建议使用) - 第二个参数为延迟毫秒数,可选的,默认值为
0. - 第三个及后面的参数为函数的入参。
setTimeout的返回值是一个数字,这个值为timeoutID,可以用于取消该定时器
# setTimeout在浏览器中的实现
- 浏览器渲染进程中所有运行在主线程上的任务都需要先添加到消息队列,然后事件循环系统再按照顺序执行消息队列中的任务。
- 在 Chrome 中除了正常使用的消息队列之外,还有另外一个消息队列(我们可以称为延迟队列),这个队列中维护了需要延迟执行的任务列表,包括了定时器和 Chromium 内部一些需要延迟执行的任务。所以当通过 JavaScript 创建一个定时器时,渲染进程会将该定时器的回调任务添加到延迟队列中。
比如这样的一段代码:
function foo(){
console.log("test")
}
var timeoutID = setTimeout(foo,100);
当通过 JavaScript 调用
setTimeout设置回调函数的时候,渲染进程将会创建一个回调任务,包含了回调函数foo、当前发起时间、延迟执行时间等,其模拟代码如下所示
struct DelayTask{
int64 id;
CallBackFunction cbf;
int start_time;
int delay_time;
};
DelayTask timerTask;
timerTask.cbf = foo;
timerTask.start_time = getCurrentTime(); //获取当前时间
timerTask.delay_time = 100;//设置延迟执行时间