关于for循环中使用setTimeout的四种解决方案零基础入门_循环使用指南

我们先来简单了解一下setTimeout延时器的运行机制。setTimeout会先将回调函数放到等待队列中,等待区域内其他主程序执行完毕后,按时间顺序先进先出执行回调函数。本质上是作用域的问题。因此若是这样将不会得到想要的结果输出1.2.3.4.5,而会连续输出5个6。for (var i=1; i<=5; i++) {setTimeout( functio

关于for循环中使用setTimeout的四种解决方案零基础入门

我们先来简单了解一下setTimeout延时器的运行机制。setTimeout会先将回调函数放到等待队列中,等待区域内其他主程序执行完毕后,按时间顺序先进先出执行回调函数。本质上是作用域的问题。

关于for循环中使用setTimeout的四种解决方案零基础入门_循环使用指南

因此若是这样将不会得到想要的结果输出1.2.3.4.5,而会连续输出5个6。

for (var i=1; i<=5; i++) {
    setTimeout( function timer() {
        console.log( i );
     }, i*1000 );
}

这是因为setTimeout是异步执行,每一次for循环的时候,setTimeout都执行一次,但是里面的函数没有被执行,而是被放到了任务队列里,等待执行。只有主线上的任务执行完,才会执行任务队列里的任务。也就是说它会等到for循环全部运行完毕后,才会执行fun函数,但是当for循环结束后此时i的值已经变成了6,因此虽然定时器跑了5秒,控制台上的内容依然是6。

(注意:for循环从开始到结束的过程,需要维持几微秒或几毫秒,当定时器跑完一秒之后for循环早已经做完了。)

我们来看另一种情况:

for (var i=1; i<=5; i++) {
    (function() {
        setTimeout( function timer() {
            console.log( i );
        }, i*1000 );
    })();
}

由setTimeout的运行机制可以知道,首先会运行外部的所有主程序,虽然for循环内形成了闭包,但是fun并没有发现一个实参所以跟第一个例子并无实际差别,仍然是连续输出5个6。

解决方案1:闭包

使用闭包是很经典的一种做法:

for (var i=1; i<=5; i++) {
    (function(j) {
        setTimeout( function timer() {
            console.log( j );
        }, j*1000 );
    })(i);
}

我们可以发现跟预期结果一致,依次输出1到5,因是因为实际参数跟定时器内部的i有强依赖。

通过闭包,将i的变量驻留在内存中,当输出j时,引用的是外部函数的变量值i,i的值是根据循环来的,执行setTimeout时已经确定了里面的的输出了。

解决方案2:拆分结构

我们还可以将setTimeout的定义和调用分别放到不同部分:

function timer(i) {
    setTimeout( console.log( i ), i*1000 );
}
for (var i=1; i<=5;i++) {
    timer(i);
}

控制台上输出依然是依次输出1到5。


解决方案3:let

这里再来说一说使用es6的let来解决此问题:

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

这个例子与第一个相比,只是把var更改成了let,可是控制台的结果却是依次输出1到5。

因为for循环头部的let不仅将i绑定到for循环中,事实上它将其重新绑定到循环体的每一次迭代中,确保上一次迭代结束的值重新被赋值。setTimeout里面的function()属于一个新的域,通过var定义的变量是无法传入到这个函数执行域中的,通过使用let来声明块变量能作用于这个块,所以function就能使用i这个变量了;这个匿名函数的参数作用域和for参数的作用域不一样,是利用了这一点来完成的。这个匿名函数的作用域有点类似类的属性,是可以被内层方法使用的。

解决方案4:setTimeout第三个参数

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

由于每次传入的参数是从for循环里面取到的值,所以会依次输出1到5。关于setTimeout第三个参数,下一篇会详细讲到,这里大家了解下就好。

海计划公众号
(0)
上一篇 2020/03/22 01:27
下一篇 2020/03/22 01:27

您可能感兴趣的内容

  • NodeJS模块Buffer入门百科_模块指南攻略

    Buffer 作为 nodejs 中重要的概念和功能,为开发者提供了操作二进制的能力。本文记录了几个问题,来加深对 Buffer 的理解和使用:认识缓冲器如何申请堆外内存如何计算字节长度如何计算字节长度如何转换字符编码理解共享内存与拷贝内存认识 Buffer(缓冲器)Buffer 是 nodejs 核心 API,它提供我们处理二进制数据流的功能。Buffer

    2020/03/20
  • JS树结构操作:查找、遍历、树结构和列表结构相互转换小白攻略_树基础入门

    经常有同学问树结构的相关操作,也写了很多次,在这里总结一下JS树形结构一些操作的实现思路,并给出了简洁易懂的代码实现。本文内容结构大概如下:一、遍历树结构1. 树结构介绍JS中树结构一般是类似于这样的结构:let tree = [{id: ‘1’,title: ‘节点1’,children: [{id: ‘1-1’,title: ‘节点1-1’},{id:

    2020/03/22
  • 万能瀑布流菜鸟攻略_瀑布流小白知识

    常见的瀑布流实现大部分只适用于子块尺寸固定或内部有图片异步加载的情况。而对于子块有图片这种可能引起尺寸变化的情况,通常的做法是写死图片高度,或检测内部的 img 元素从而在 onload 事件中进行重排。由于我们业务中尺寸变化情况更为复杂,如子块本身异步初始化、内部数据异步获取,且这种尺寸变化时机不可确定,为满足这种需求所以调研完成了一个通用万能的瀑布流实现

    2020/03/21
  • Kraken.js基础知识基于 express 构建,实现对环境变量的感知、动态配置、高级中间件和应用生命周期的事件通知

    Kraken.js基础入门 官方网址:http://krakenjs.com/ GitHub:https://github.com/krakenjs/kraken-js 简介描述:…

    2020/03/05
  • 什么是单点登录?入门基础知识_登录基础知识教程

    在日常工作中,用户需要访问大量的信息资源,例如,用户首先要登录到操作系统中,然后进入各个应用系统。进入每一个系统都需要对用户的身份进行识别与验证,这样,用户需要提供多个用户帐号与口令,为了便于记忆,用户很可能把各种帐号与口令信息记录在笔记本上,甚至写在便条上并贴在办公桌或屏幕边,这就使口令信息很容易泄露出去,增加了组织信息系统被入侵的安全风险。为了解决这个问

    2020/03/26
  • 怎么彻底删除nodejs?菜鸟教程_node入门基础教程

    怎么彻底删除nodejs?菜鸟教程 Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台。Node.js是一个事件驱动I/O服务端JavaScript…

    2020/03/20
  • fastclick菜鸟指南_消除移动端浏览器上的点击事件的 300ms 的延迟

    fastclick菜鸟指南 官方网址:http://ftlabs.github.io/fastclick/ GitHub:https://github.com/ftlabs/fas…

    2020/03/06
  • 常用SQL语句分享使用教程_sql基础知识

    前言:日常工作或学习过程中,我们可能会经常用到某些SQL,建议大家多多整理记录下这些常用的SQL,这样后续用到会方便很多。笔者在工作及学习过程中也整理了下个人常用的SQL,现在分享给你!可能有些SQL你还不常用,但还是希望对你有所帮助,说不定某日有需求就可以用到。注:下文分享的SQL适用于MySQL 5.7 版本,低版本可能稍许不同。有些SQL可能执行需要较

    2020/03/24
  • jenkins小白知识_支持构建、部署、自动化

    jenkins小白知识 官方网址:https://jenkins.io/zh/ GitHub:https://github.com/jenkinsci 简介描述:支持构建、部署、自…

    2020/03/06
  • sublime3快捷键大全与注意事项基础入门_快捷键基础教程

    sublime3_Mac快捷键编辑快捷键:cmd+L:选择行(重复按下将下一行加入选择);cmd+D:选择词(重复按下时多重选择相同的词进行多重编辑);cmd+shift+D 复制光标所在整行,插入到下一行control+shift+M:选择括号的内容;cmd+shift+enter:在当前行前插入新行;cmd+enter:在当前行后插入新行;control

    2020/04/05
  • 酷站代码小白教程_网页特效,js特效,jQuery特效,js代码大全

    酷站代码小白教程 官方网址:http://www.5icool.org/ 简介描述:网页特效,js特效,jQuery特效,js代码大全 精选网站特效源码,提供jQuery特效、js…

    2020/03/06
  • CDN与DNS知识汇总指南攻略CDN/DNS是什么?有什么好处?_CDN入门基础

    在性能优化的时候,比较常见的一个建议是,把资源部署在CDN上,那么问题来了,CDN是什么?这样做有什么好处?DNS我们先讲一下域名系统DNS(Domain Name System)吧。他是一个分布式数据库,功能是联系域名和ip地址。域名与ip的对应关系,被称为记录(record),可分为各种类型A: Address,域名指向的IP地址,一个域名可以有多个A记

    2020/04/05
  • Js之DOM事件机制入门攻略_机制入门基础教程

    一、事件机制事件是在编程时系统内发生的动作或者发生的事情,系统会在事件出现的时候触发某种信号并且会提供一个自动加载某种动作的机制(来自MDN)。每个事件都有事件处理器(有时也叫事件监听器),也就是触发事件时运行的代码块。严格来说事件监听器监听事件是否发生,然后事件处理器对事件做出反应。二、DOM事件流事件传播是一种机制,用于定义事件如何传播或通过DOM树传播

    2020/03/23
  • 成为一流软件开发者的 34 条建议使用帮助_建议指南教程

    我们列出了一张包含 34 条建议的清单,来帮助你成为一流的软件开发者,在技术行业中打造出成功的职业生涯。这些建议中,有一些是特别针对增强编程技能的,其他的一些建议则是软件开发职业生涯中的软技能,还有些甚至能够帮助你成为一个更好的人。1. 规划方法 & 在编码前先写伪代码当你试图构建一个项目或者完成一个任务时,如果没有规划就直接开始编写代码,可能会浪费大量时间

    2020/03/23
  • 免费下载视频、图片素材的网站基础知识教程_网站小白知识

    videezy高清视频下载,免登录,就可以下载,不用翻墙带宽很足; 是一个成立于2006年的平面设计师素材分享站点,平面设计师Shawn发现要想在网络中找一些不错的素材很麻烦,于是就出版了针对平面设计师的素材站点,2010年开始团队运营,现在网站以分享免费的高清视频素材为主,用户可根据许可证免费使用。网站:https://www.videezy.com/p

    2020/04/03
  • SVG-edit基础入门_一个快速的,基于Web的,由JavaScript驱动的SVG绘图编辑器

    SVG-edit基础入门 GitHub:https://github.com/SVG-Edit/svgedit 简介描述:一个快速的,基于Web的,由JavaScript驱动的SV…

    2020/03/10