setTimeOut 和 setInterval对比

  1. 概念
    在规定时间内自动执行某个函数;定时器又分为延时定时器和间歇定时器,即 setTimeOut 和 setInterval

  2. 定时器的创建和清除

    1. 延时定时器
     function fn(){
         console.log('setTimemOut')
     }
     const timer = setTimeOut(fn, 100) // timer为定时器ID
     clearTimeOut(timer)
    
    1. 间歇定时器
     function fn(){
         console.log('setTimemOut')
     }
     const timer = setInterval(fn, 100)  // timer为定时器ID
     clearInterval(timer)
    
  3. 用 setTimeOut 模拟 setInterval

    let num = 100
    function count(){
        num --
        timer = setTimeout(count,86400000);//递归调用延迟定时器
        if(num == 0){
            clearTimeout(timer);//清除定时器
        }
     }
     timer = setTimeout(count,86400000);//创建延迟定时器
    
  4. 区别
    setTimeOut 的间隔时间为设置的间隔时间加本身函数的执行时间,即 console 执行的时间 + 100

    function run() {
        console.log('其他代码执行时间')
        setTimeOut(function() {
            console.log(111)
        }, 100)
    }
    

    setInterval 的间隔时间就是为设置的间隔时间,即就是 100

    function run() {
        console.log('其他代码执行时间')
        setInterval(function() {
            console.log(111)
        }, 100)
    }
    
  5. setTimeOut(fn, 0) 问题
    javascript 为单线程,意味着所有的任务都需要排队,前一个任务完成后一个任务才会执行。
    而浏览器为多线程,至少可以实现 3 个常驻线程:引擎线程、渲染线程、事件触发线程。

    1. javascript 引擎是基于事件驱动单线程执行的,JS 引擎一直等待着任务队列中任务的到来,然后加以处理,浏览器无论什么时候都只有一个 JS 线程在运行 JS 程序。
    2. GUI 渲染线程负责渲染浏览器界面,当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行。但需要注意 GUI 渲染线程与 JS 引擎是互斥的,当 JS 引擎执行时 GUI 线程会被挂起,GUI 更新会被保存在一个队列中等到 JS 引擎空闲时立即被执行。
    3. 事件触发线程,当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待 JS 引擎的处理。这些事件可来自 JavaScript 引擎当前执行的代码块如 setTimeOut、也可来自浏览器内核的其他线程如鼠标点击、AJAX 异步请求等,但由于 JS 的单线程关系所有这些事件都得排队等待 JS 引擎处理。(当线程中没有执行任何同步代码的前提下才会执行异步代码)。

    总结:所以当 js 代码遇到 setTimeOut 时,会把延时执行的函数置于任务队列中,当 js 引擎线程空闲时并到达延时的时间时,才会把函数置于 js 引擎线程中执行。拿 4 中的 run 来举例就是:首先浏览器会把 console.log()置于 js 引擎线程,然后把定时器置于任务队列中,当 console.log()执行完成,且没有其他的同步任务了,就会去任务队列中取定时器里面的任务置于 js 引擎线程中,然后执行它。
    因此,setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,也就是说,尽可能早得执行。它在"任务队列"的尾部添加一个事件,因此要等到同步任务和"任务队列"现有的事件都处理完,才会得到执行。

  6. setTimeOut 用处

    1. 函数防抖
    const debounce = function(fn) {
        const timer = null
        return function() {
            let self = this
            if(timer) {
                clearTimeOut(timer)
            }
            timer = setTimeOut(function() {
                fn.call(this, arguments)
            }, 300)
        }
    }
    
    1. 轮询, 模拟 interval
    setTimeOut(function() {
        console.log('执行')
        setTimeOut(arguments.callee, 100)
    })
    
posted @ 2021-01-11 11:09  Tutao1995  阅读(115)  评论(0编辑  收藏  举报