你不知道的setTimeout

2022-09-29 19:13:48 浏览数 (2)

前言

setTimout 在日常开发中或多或少都会用到,以前可能仅限于使用,但是对其原理了解的比较浅,因此此文会更加深入的去了解其作用和原理。

本文的主要内容包括:

  • 基本用法
  • setTimout(fn, 0)执行时机
  • 使用场景

基本用法

setTimout 是一个全局方法,可以通过window对象访问,也可在 web worker 中使用。其主要作用是设置一个定时器,该定时器在指定的时间后执行指定的代码段或者函数。先举个例子在来具体看看其使用:

代码语言:javascript复制
let timer = setTimeout((...params) => {
  console.log( ...params)
}, 1000, 'setTimeout');
// 1s后打印出 setTimeout,

可以看到调用模式如下:

代码语言:javascript复制
let timer = setTimout(fn, delay, params)

参数:fn 为要执行的函数或者代码段, delay 是延迟执行的时间,单位为ms,其余的参数是要传入fn 中使用的值,也可没有;

返回值: 一个正整数,表示定时器编号;可以使用clearTimout(timer) 取消设定的定时器

setTimout(fn, 0)执行时机

我们先看这样一段代码

代码语言:javascript复制

setTimeout(() => {
  console.log('setTimeout')
}, 0);

console.log('main script');

这段代码会输入什么呢,按理说 0ms 表示立即执行,应该是先输出 setTimout 然后在输出 main script,其打印顺序和其原理有关。

尽管setTimeout 以0ms的延迟来调用函数,但这个任务已经被放入了队列中并且等待下一次执行;并不是立即执行;队列中的等待函数被调用之前,当前代码必须全部运行完毕。这也就是为什么会出现先打印 `main script `的原因。

值得注意的是如果当前任务执行的时间较长并且超过定时器设定的时间,那么定时任务会超时执行。如:

代码语言:javascript复制
let startTime = performance.now();
setTimeout(() => {
  console.log('setTimeout');
  let endTime = performance.now();
  console.log(endTime - startTime);
}, 50);

for(let i = 0; i < 10000000; i  ) {
  //do something;
}
// 定时器会超过50ms 后在执行

使用场景

setTimout使用场景较多,列举一两个例子抛砖引玉,相信读者会有更多的妙用。

防抖:比如在支持input 输入查询时,我们会监听onBlur 函数获取搜索词然后调用后台接口查询,但是我们并不希望查询频率过高,可是使用防抖函数。具体实现如下:

代码语言:javascript复制
const debounce = function(fn, delay) {
  let timer;
  let context;
  return function(){
    context = this;
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, arguments)
    }, delay)
  }
}
// 调用实例,虽然调用了两次只会打印一次
let debounceLog = debounce(() => {
  console.log(2)
},50);
debounceLog();
debounceLog();

轮询

有时需要不断的获取某个数据最新的状态,那么可使用setTimoute来实现,伪代码如下:

代码语言:javascript复制
function fetchData() {
  // 获取数据
  data = fetch(params);
  
  // 定时拉取
  setTimeout(fetchData, 1000)
}

0 人点赞