在for循环中运行setTimeout是前端开发很常见的一种模式。最近被考了一道相关的题目觉得很有意思也很容易犯错,于是记录下来当做学习笔记。
下面先来看一段代码:

   for(var i=0;i<10;i++){setTimeout(console.log(i),0);}

看完这段代码思考一下结果输出是什么呢?
是不是第一时间想到的是连续的10个10呢?啊哈哈这样就错啦~
答案是0、1、2、3、4、5、6、7、8、9哦,这是因为很多人把这段代码与下面的代码混淆了

 for(var i=0;i<10;i++){setTimeout(function(){console.log(i);  //连续的10个10},0);}

这段代码输出结果是连续的10个10。
首先我们来说一下为什么是连续的10个10。因为在for循环中使用setTimeout涉及到了异步机制。说到异步机制那就要说一下JS的运行机制。
JS是单线程环境,也就是说代码的执行是从上到下,依次执行。也就是同一个时间只能做一件事

单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。JavaScript将所有任务分成两种,一种是同步任务,另一种是异步任务。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

在所有同步任务执行完之前,任何的异步任务是不会执行的。 而setTimeout就是一个异步任务,所以会先执行for循环这个同步任务,把setTimeout()放进任务队列中等待主线程的for循环执行完毕,一旦"执行栈"中的所有同步任务执行完毕(循环结束后此时i=10)就会从队列中取出setTimeout()
for循环一次碰到一个 setTimeout(),并不是马上把setTimeout()拿到异步队列中,而要等到一秒后,才将其放到任务队列里面。

异步执行的运行机制如下:

  1. 所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
  2. 主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
  3. 一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
  4. 主线程不断重复上面的第三步。
    主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。这个过程会循环反复。

一般来说,有以下四种会放入异步任务队列:

  1. setTimeout和setlnterval
  2. DOM事件
  3. ES6中的Promise
  4. Ajax异步请求

回归正题,既然在for循环中运行setTimeout()涉及到了异步,那上面的解释不就解决问题了吗,可是为什么第一段代码结果不是连续的10个10呢?这就涉及到了console.log 与console.log()的区别了。
看下面代码:

看懂了吗,看懂了这道题也就解决了啊哈哈
其实console.log 与console.log()的区别就是 console.log()是立即执行的也就是IIFE,而console.log只是一个function 函数名。所以console.log()是同步任务跟for循环是同步执行的,而setTimeout()是异步任务需要等到主线程的同步任务执行完毕后才能执行,所以结果就是0、1、2、3、4、5、6、7、8、9了。

再来看一段代码:

 for(var i=0;i<10;i++){setTimeout("console.log(i)",1000);//连续的10个10}

啊哈哈,这时候结果就是连续的10个10了。

原因在于加了双引号的console.log()不再是立即执行函数。setTimeout() 会判断第一个参数是否是[function],如果不是,则会尝试将它当做字符串处理。也就是说,console.log(i)执行后的返回值转为字符串。

现在明白在for循环中运行setTimeout()的三种情况区别了吧

 for(var i=0;i<10;i++){setTimeout(console.log(i),0);//0、1、2、3、4、5、6、7、8、9}for(var i=0;i<10;i++){setTimeout(function(){console.log(i);//连续的10个10},0);}for(var i=0;i<10;i++){setTimeout("console.log(i)",1000);//连续的10个10}

我之前写过一篇有关的牛客错题解析
https://blog.csdn.net/Febby_/article/details/89513819

异步知识参考来源:
https://baijiahao.baidu.com/s?id=1615713540466951098&wfr=spider&for=pc

希望能够帮到大家~~

在for循环中运行setTimeout的三种情况相关推荐

  1. ES6中let的用法及一个小案例,在for循环中运行setTimeout的四种情况:

    1.ES6中let和var的主要区别: (1)let声明的变量只在当前块级作用域内有效. if(true){var a=1;let b=2; } console.log(a); console.log ...

  2. js setTimeout的三种情况

    在for循环中运行setTimeout是前端开发很常见的一种模式.最近被考了一道相关的题目觉得很有意思也很容易犯错,于是记录下来当做学习笔记. 下面先来看一段代码: for(var i=0;i< ...

  3. 在for循环中运行setTimeout

    先看一段代码 for (var i=0; i<10; i++) { setTimeout(console.log(i), i*1000 );} 答案:0.1.2.3.4.5.6.7.8.9 再比 ...

  4. C++必须使用【初始化列表】初始化数据成员的三种情况

    类对象的构造顺序是这样的: 1.分配内存,调用构造函数时,隐式/显示的初始化各数据成员: 2.进入构造函数后在构造函数中执行一般赋值与计算. 使用初始化列表有两个原因: 原因1.必须这样做: < ...

  5. 你不知道的三种在for循环中使用setTimeout的方法

    在 for 循环中使用 setTimeout 中可能会出现结果输出不符合预期: for (var i = 0; i < 5; i++) {setTimeout(() => {console ...

  6. 问题:数组的循环左移。要求设计三种算法,将数组中的N个元素能够实现循环左移p个位置。

    问题重述:数组的循环左移.要求设计三种算法,将数组中的N个元素能够实现循环左移p个位置. 算法1: 先将数组中的前p个元素存放在一个临时数组中,再将余下的N-p个元素左移p个位置,最后将前p个元素从临 ...

  7. java 终止方法_Java中终止线程的三种方法

    Java中终止线程的三种方法 Thread.stop, Thread.suspend, Thread.resume 和Runtime.runFinalizersOnExit 这些终止线程运行的方法已经 ...

  8. 【在PowerPoint中插入视频的三种方法】

    为了能更好地帮助大家合理地在PowerPoint课件中插入和播放视频文件, 在PowerPoint中插入视频的三种方法 ,本文特向大家介绍PowerPoint中插入和处理视频的三种方法. 直接播放视频 ...

  9. java里break的使用方法_Java中break的第三种用法说明

    在Java中,break语句有三种用法,第一种是用于终止switch语句中的语句序列,第二种是用于退出循环,然而第三种是用作goto语句的"文明"形式! 我们知道,goto语句会破 ...

最新文章

  1. shell脚本中echo显示内容带颜色的实现方法
  2. 数据中心机房的一些空调制冷办法详解!
  3. owls-uddi-matchmaker安装
  4. 关于WPF中TextBox使用SelectAll无效的问题的解决办法
  5. js等待当前线程内ajax完成,理解javascript定时器中的单线程
  6. Java设计模式之策略设计模式
  7. hashmap 遍历_别慌,送你21 个面试官必问HashMap考点
  8. 获取http地址如何从上面抓取图片_用 Python 自动抓取妹子图
  9. Ranger-Solr审计日志安装
  10. 数据结构 Tricks(一)—— 父节点和左右孩子索引号之间的关系
  11. [转载] python开源人工智能项目_推荐 10 个饱受好评且功能独特的开源人工智能项目
  12. 编程入门书籍:大学学习计算机基础必读 5 本经典入门书籍,收藏
  13. Threejs实现3d地球记录(1)
  14. Android:短信的接收
  15. 字符串分割、切片、替换、去除头尾指定字符
  16. 一些实用高效的装机软件汇总
  17. HDU - 5974 A Simple Math Problem 题解
  18. 离散元 python_刚开始学习离散元软件Yade,有什么建议?
  19. 【高等数学】基础理论归纳
  20. 1800个python词汇_基本 Python 词汇

热门文章

  1. STM32---ucosii和ucosiii
  2. 三月c++面经(英特尔、旷世、云从、地平线,具体回答后续补)
  3. iframe嵌入通讯
  4. Andoird conflicts with another tag that has the same ID
  5. 聊聊chatbot那些事
  6. 国外电子工程师们国内电子工程师火拼(转)
  7. 【详细搭建教程】在线客服系统源码3.0防黑版,即时聊天通讯源码 带机器人,防注入 无后门
  8. 【SQL Server】列转行 STUFF 函数
  9. 什么是软件可靠性测试?
  10. 记2019.7日照夏令营