在For循环中执行setTimeOut()方法的代码,执行顺序是怎样的呢?

代码如下

function time() {
  for(var i= 0;i<5;i++){
    setTimeout(function () {
      console.log(i);
    },1000)
  }
}
time();

应该会有人会说,很简单呀,for循环进行遍历,并且每次有一个输出,那结果应该是0,1,2,3,4。

其实不然,运行上诉代码之后,控制台输出如下:5个5

下面解释下为什么是5个5.

首先关于最开始贴的代码,我们是想让计算机每循环一次的时候都会进入到setTimeOut()方法里执行console.log,输出i之后再执行下一次循环。但是在JS里却并不是这样的。因为setTimeOut() 是一个异步函数,什么是异步函数呢?

首先我们都知道JS的执行机制是单线程环境。什么是单线程环境?打个比方,多线程就相当于一条公路上有多个车道,一次可以通过多辆车子。单线程就相当于这条公路就只有一个车道,每次只能通过一辆车。同理,在JS的单线程环境里,每次只能从上到下一条一条的把代码执行下去。但是这样一条一条按顺序执行下去有的时候在面对特殊要求的时候速度太慢了。例如这条单车道的公路上现在要通行一辆救护车,救护车要是等到车道里的车子都通过了才能走那就太浪费时间了,不符合要求。那怎样才能让救护车以最快的速度通过这条单车道呢?这时候就引入了一个异步函数的概念。异步函数不是按正常代码那样要按顺序等前面的代码都执行完了才执行自己,当JS遇到异步函数的时候,会把异步函数插入到队列中等待。也就是所谓的插队。而setTimeOut 就是一个异步函数。所以当JS检测到setTimeOut()的时候,会把setTimeOut()插入到队列中,然后继续执行后面的代码,也就是接下来的循环。由于setTimeOut()设置了一秒后才执行,所以插入的队列位置是一秒后。而在这个一秒内for循环已经全部完成,i经过五次循环后变成了5。所以当一秒后开始执行setTimeOut()方法的时候i的值已经变成5了。因为循环了5次,所以有5次setTimeOut()方法的调用,即输出5个5。

用代码表示的话就是我们最开始设想的流程是这样的:

for(i=0) ——> console.log(0) ——> for(i=1) ——> console.log(1) ——> for(i=2) ——> console.log(2) ——> for(i=3) ——> console.log(3) ——> for(i=4) ——> console.log(4) ——> for(i=5) ——> 执行结束

但是在实际中的流程是这样的:

for(i=0) ——> for(i=1) ——> for(i=2) for(i=3) ——> for(i=4) ——> for(i=5)ps:(这段循环都在一秒内完成了)——> console.log(5) ——> console.log(5) ——> console.log(5) ——> console.log(5) ——> console.log(5) ——> 执行完成

那么有什么办法可以避免呢?

目前来看方法应该还是很多的,我目前知道的有三个,其他的方法有兴趣可以自己再百度一下。

第一个方法的思路很简单,因为setTimeOut()是异步执行,所以我们让它立即执行就可以了。

for (var i = 0; i < 5; i++) {
(function (i) {
setTimeout(function () {
      console.log(i);
  }, 1000 * i);
})(i); //这里使用闭包
}

这段函数会让JS检测到setTimeOut时不再放到队列中进行等待,而是立即运行setTimeOut()。所以能按我们所想的进行输出。

第二个方法是使用let而不是var。即:

for (let i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, 1000 * i);
}

为什么let就行而var不行呢?因为let的作用域是块作用域,所以每次JS检测到setTimeOut把setTimeOut放到队列的同时,let定义的i的值也会跟随setTimeOut进去队列。所以每次循环后队列里的setTimeOut里的i的值是不一样的。而var定义的i是无法进入setTimeOut的。i只能在运行到setTimeOut时才会向外层环境申请i的值,而这个时候i的值已经变成5了。

部分转自:https://blog.csdn.net/qq_38054172/article/details/100764630

JS中For循环中嵌套setTimeout()方法的执行顺序的更多相关文章

  1. 在Spring Bean的生命周期中各方法的执行顺序

    Spring 容器中的 Bean 是有生命周期的,Spring 允许在 Bean 在初始化完成后以及 Bean 销毁前执行特定的操作,常用的设定方式有以下十种: 通过实现 InitializingBe ...

  2. C#类中方法的执行顺序

    有些中级开发小伙伴还是搞不太明白在继承父类以及不同场景实例化的情况下,父类和子类的各种方法的执行顺序到底是什么,下面通过场景的举例来重新认识下方法的执行顺序: (下面内容涉及到了C#中的继承,构造函数 ...

  3. js 关于setTimeout和Promise执行顺序问题

    js 关于setTimeout和Promise执行顺序问题 异步 -- Promise和setTimeout 执行顺序   Promise 和 setTimeout 到底谁先执行 定时器的介绍 Jav ...

  4. 简单理解Struts2中拦截器与过滤器的区别及执行顺序

    简单理解Struts2中拦截器与过滤器的区别及执行顺序 当接收到一个httprequest , a) 当外部的httpservletrequest到来时 b) 初始到了servlet容器 传递给一个标 ...

  5. 关于java中构造方法、实例初始化、静态初始化执行顺序

    在Java笔试中,构造方法.实例初始化.静态初始化执行顺序,是一个经常被考察的知识点. 像下面的这道题(刚刚刷题做到,虽然做对了,但是还是想整理一下) 运行下面的代码,输出的结果是... class ...

  6. js的for循环中出现异步函数,回调引用的循环值总是最后一步的值?

    这几天跟着视频学习node.js,碰到很多的异步函数的问题,现在将for循环中出现的异步函数回调值的问题总结如下: 具体问题是关于遍历文件夹中的子文件夹的,for循环包裹异步函数的代码: for (v ...

  7. js模版引擎handlebars.js实用教程——循环中使用索引

    <!DOCTYPE html> <html> <head> <META http-equiv=Content-Type content="text/ ...

  8. js中页面加载完成后执行的几种方法及执行顺序

    在js和jquery使用中,经常使用到页面加载完成后执行某一方法.通过整理,大概是五种方式(其中有的只是书写方式不一样). 1:使用jQuery的$(function){}; 2:使用jquery的$ ...

  9. 零基础学习java------day5------do....while循环、嵌套、方法(函数)

    1  do...while循环 格式 初始化语句; do { 循环体语句; 控制条件语句; }while(判断条件语句); 流程: 先执行初始化语句 再执行循环体语句 再执行条件控制语句 再做条件的判 ...

随机推荐

  1. sh_02_快速体验

    sh_02_快速体验 import sh_01_九九乘法表 sh_01_九九乘法表.multiple_table()

  2. prometheus-pushgateway安装

    背景 当prometheus的server与target不在同一网段网络不通,无法直接拉取target数据,需要使用pushgateway作为数据中转点. 弊端 将多个节点数据汇总到 pushgate ...

  3. D2. Equalizing by Division (hard version)

    D2. Equalizing by Division (hard version) 涉及下标运算一定要注意下标是否越界!!! 思路,暴力判断以每个数字为到达态最小花费 #include<bits ...

  4. iterator删除元素

    总结 在需要的删除等操作时,不能使用简单的foreach,因为其底层依然用的是Iterator,但是调用的是集合中的remove方法. 使用迭代器对象调用其中的remove方法,以保证线程同步.

  5. Android由出生年月日计算年龄(周岁)

    先从String类型的出生日期(“yyyy-MM-dd”)中提取int类型的年.月.日:再计算岁数. 程序如下: /** * 根据出生日期计算年龄的工具类BirthdayToAgeUtil */ pu ...

  6. 初步理解JS的事件机制

    一.事件流(捕获,冒泡)   事件流:指从页面中接收事件的顺序,有冒泡流和捕获流. 当页面中发生某种事件(比如鼠标点击,鼠标滑过等)时,毫无疑问子元素和父元素都会接收到该事件,可具体顺序是怎样的呢?冒 ...

  7. ArcCatalog连接远程ArcGIS Server服务器

    注意:本地机器登陆的用户名和密码必须与ArcGIS Server服务器上的用户名和密码完全一致,并加入到agsadmin和agsuser组中.重启电脑.   (其实就是在自己的电脑上建立一个用户名,这 ...

  8. Nova 的高性能虚拟机支撑

    目录 目录 CPU 计算平台体系架构 SMP 架构 NUMA 结构 MMP 结构 Nova 的高性能虚拟机 Nova 虚拟机 CPU/RAM 设计的背景 操作系统许可(Licensing) 性能(Pe ...

  9. 用 Python 解答两道来自阿里伯乐系统的笔试题

    目录 目录 前言 题目一 分析 实现 题目二 分析 实现 前言 朋友到阿里面试,分享两道小题,博主比较闲就试着用 Python 解答一下,实现方式肯定是多种多样的,优劣也会各有不同,欢迎交流. 题目一 ...

  10. Apache web服务器(LAMP架构)

    1.apache介绍 1).世界上使用率最高的网站服务器,最高时可达70%:官方网站:apache.org 2).http 超文本协议 HTML 超文本标记语言 3).URL 统一资源定位符 http ...