setTimeout的理解
setTimeout到底是同步还是异步的 ?
定时器会在当前任务队列执行完之后才会执行定时器的回调
需要注意的是,setTimeout()只是将事件插入了"任务队列",必须把当前任务队列执行完之后才会执行定时器的回调。要是当前任务队列耗时很长,有可能要等很久,所以并没有办法保证,回调函数一定会在setTimeout()指定的时间执行。
综上所属 setTimeout是单线程,类似异步,但不是异步 。
- 异步的三种实现方式
- 回调函数, 回调函数不一定是异步 , 但异步一定有回调函数
- 事件
- promise对象
setTimeout时间设置为0的理解
setTimeout(function(){
console.log(1);
}, 0);
console.log(2);
console.log(3);
- 得到的结果竟然是2、3、1
为啥呢?
- js是单线程的,单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着
- 当一个事件被触发时该线程会把事件添加到待处理任务队列的队尾
- 当js代码执行遇到
setTimeout(fn,millisec)时,会把fn这个函数放在任务队列中,会把fn这个函数放在任务队列中,当js引擎线程空闲时并达到millisec指定的时间时,才会把fn放到js引擎主线程中执行。 setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,也就是说,尽可能早得执行。它在"任务队列"的尾部添加一个事件,因此要等到同步任务和"任务队列"现有的事件都处理完,才会得到执行。
setTimtout定时器的时间一定准吗?
- 不一定准,因为js是单线程的,定时器会在当前任务队列执行完之后才会执行定时器的回调
- 假如当前队列任务执行时间大于定时器设置的延迟时间,那么定时器就不是那么可靠
定时器的第三个参数列表
- 第三个参数是可选,可添加多个参数, 用来传递给回调函数的参数
- 第三个参数还可以是先执行,然后再执行回调函数
为什么setTimeout会有4ms的延时?
- 按照 W3C 的标准,浏览器实现计时器时,如果嵌套层级超过5层,则会带有4毫秒的最少时间
如何实现一个setTimeout?/如何实现准时的setTimeout?
- 1、requestAnimationFrame
- 2、performance.now()
- 通过时间调整间隔偏差
- 3、webworker 【推荐】
- 通过新开一个新的后台线程,去完成计时操作,不受主线程的影响
- 可封装一个通用的webworker来实现定时器
requestAnimationFrame与setTimeout相比,requestAnimationFrame 最大的优势是由浏览器来决定回调函数的执行时机
performance.now()返回当前时间(以毫秒为单位),因此可以跟踪从调用setTimeoutRAF开始到当前时间的时间间隔- 如果时间间隔大于给定的延迟,则会调用回调函数,否则会再次调用requestAnimationFrame
1、注意: requestAnimationFrame的执行频率取决于浏览器的刷新率,并且可能会受到其他因素的影响
2、performance.now() 与页面加载有关,Date.now() 依赖于系统的时间
function setTimeoutRAF(callback, delay) {
let start = performance.now();
function timeout() {
let elapsed = performance.now() - start;
if (elapsed >= delay) {
callback();
} else {
requestAnimationFrame(timeout);
}
}
requestAnimationFrame(timeout);
}
例如,要在2秒后调用回调函数,可以这样调用setTimeoutRAF:
Copy codesetTimeoutRAF(() => {
console.log('2 seconds have passed');
}, 2000);
setTimeout时间设置为0的理解
setTimeout(function(){
console.log(1);
}, 0);
console.log(2);
console.log(3);
- 得到的结果竟然是2、3、1
为啥呢?
- js是单线程的,单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着
- 当一个事件被触发时该线程会把事件添加到待处理任务队列的队尾
- 当js代码执行遇到
setTimeout(fn,millisec)时,会把fn这个函数放在任务队列中,会把fn这个函数放在任务队列中,当js引擎线程空闲时并达到millisec指定的时间时,才会把fn放到js引擎主线程中执行。 setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,也就是说,尽可能早得执行。它在"任务队列"的尾部添加一个事件,因此要等到同步任务和"任务队列"现有的事件都处理完,才会得到执行。
定时器中的函数调用需要注意的地方
-
方式一:
函数不加括号:函数名称作为函数的指针,用于传参,此时不是得到函数的结果,因为不会运行函数体代码。它只是传递了函数体所在的地址位置,在需要的时候好找到函数体去执行。
- 不带括号的是绑定事件,事件触发再执行
函数加了括号:带括号的是函数调用,直接执行函数,返回函数结果