for循环与setTimeout的爱恨情仇

lxf2023-07-25 08:40:01

当你能从浪费时间中获得快乐时,就不算浪费时间

Examples

//test1 ==> 0 1 2 3 4 5 6 7 8 9
for(var i = 0 ;i <10;i++){
    setTimeout(
      console.log(i),
    0);
}
//test2 ==> 10个10
for(var i = 0;i<10;i++){
    setTimeout(() =>{
        console.log(i)
    },0)
}
//test3 ==> 10个10
for(var i = 0 ;i <10;i++){
    setTimeout(
      'console.log(i)',
    0);
}

详解

王德发,为什么for循环里一个setTimeout会出现这么多的花样,下面我们好好解释解释~~
在这之前我们还需要好好了解一下js的异步机制以及setTimeout参数的问题~

js的异步机制

地球人都知道js是个单线程环境,顾名思义就是js在同一时间只能干一件事,那么当任务非常多的时候,就需要有序的进行排队,直到上一个任务做完,才能做下一个任务。
当然所有事都得有个轻重缓急,js为了更好的完成任务,便将所有的任务分为了同步任务与异步任务两大类。
同步任务指的是,在主线程上排队的任务,当前一个任务执行完毕便执行后一个任务。异步任务指的是,在任务队列中排队的任务,只有任务队列通知主线程,某一个异步任务可以执行了,该任务才会进入主线程。
在异步任务中,还分为宏任务和微任务,当宏任务和微任务都处于任务队列中时,微任务的优先级大于宏任务,即在同一次事件循环中,先执行微任务再执行宏任务。
一般来说宏任务有setTimeout,setInterval,UI rendering,微任务有promise,requestAnimationFrame
我们再梳理一下,js的执行机制如下:

  1. 所有同步任务在主线程上执行,形成一个执行栈
  2. 在主线程之外,还有一个任务队列,异步任务都放置在其中,等待主线程的调用栈为空,再依次从队列中执行任务
  3. 检测队列中的微任务队列是否为空,若不为空,则取出一个微任务入栈执行,反之,则取出宏任务执行
  4. 执行完宏任务队列中的一个任务后,会继续检测微任务队列是否为空,如果有新插入的任务,就继续执行第三步,如果微任务队列为空,则继续执行宏任务的下一个任务,然后再继续循环执行第四步

这整个过程循环往复,所以又被称为Event Loop(事件循环)。

setTimeout的第一个参数问题

一般来说,我们使用setTimeout的时候,第一个参数是个函数,但是对于setTimeout来说,并没有规定第一个参数一定要是函数,它还允许使用字符串作为第一个参数,在js内部中会使用eval函数来动态执行一段字符串脚本~

setTimeout(
  'console.log(0)',
0)
==>
setTimeout(
  eval('console.log(0)'),
0)

test1解析

由此我们可以看test1的输出结果,for循环中的setTimeout是个异步任务,需要等到主线程的同步任务执行完才能执行,而console.log()立即执行函数是个同步任务,所以会跟着for循环同步执行,所以结果即0,1,2,3,4,5,6,7,8,9。

test2解析

同理,我们看test2的输出结果,当开始执行setTimeout异步任务的时候,for循环已经结束了,并且由于var声明的变量不具有快级作用域的特点,所以当for循环结束的时候,i为10,结果就会输出10个10,如果我们吧var换成let,那么结果就会变成test1的结果。

test3解析

与test1的区别在于,setTimeout第一个参数传递了一个字符串,而不再是一个立即执行函数,所以结果输出10个10。

本网站是一个以CSS、JavaScript、Vue、HTML为核心的前端开发技术网站。我们致力于为广大前端开发者提供专业、全面、实用的前端开发知识和技术支持。 在本网站中,您可以学习到最新的前端开发技术,了解前端开发的最新趋势和最佳实践。我们提供丰富的教程和案例,让您可以快速掌握前端开发的核心技术和流程。 本网站还提供一系列实用的工具和插件,帮助您更加高效地进行前端开发工作。我们提供的工具和插件都经过精心设计和优化,可以帮助您节省时间和精力,提升开发效率。 除此之外,本网站还拥有一个活跃的社区,您可以在社区中与其他前端开发者交流技术、分享经验、解决问题。我们相信,社区的力量可以帮助您更好地成长和进步。 在本网站中,您可以找到您需要的一切前端开发资源,让您成为一名更加优秀的前端开发者。欢迎您加入我们的大家庭,一起探索前端开发的无限可能!