关于for循环中使用setTimeout
我们先来简单了解一下setTimeout延时器的运行机制。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第三个参数,下一篇会详细讲到,这里大家了解下就好。
关于for循环中使用setTimeout的更多相关文章
- for循环中嵌套setTimeout,执行顺序和结果该如何理解?
这两天在捣鼓作用域的问题,有的时候知识这个东西真的有点像是牵一发而动全身的感觉.在理解作用域的时候,又看到了一道经典的面试题和例子题. 那就是在for循环中嵌套setTimeout延时,想想之前面试的 ...
- JS中For循环中嵌套setTimeout()方法的执行顺序
在For循环中执行setTimeOut()方法的代码,执行顺序是怎样的呢? 代码如下 function time() { for(var i= 0;i<5;i++){ setTimeout(fu ...
- for循环中执行setTimeout问题
代码片段: for(var i=0;i<8;i++){ setTimeout(function () { console.log(i) },0) } 输出了8次8,这跟js的执行顺序和作用域链有 ...
- 关于for循环中使用setTimeout的四种解决方案
我们先来简单了解一下setTimeout延时器的运行机制.setTimeout会先将回调函数放到等待队列中,等待区域内其他主程序执行完毕后,按时间顺序先进先出执行回调函数.本质上是作用域的问题. 因此 ...
- for循环中执行setTimeout问题(任务队列的问题)
for(var i=0;i<8;i++){ setTimeout(function () { console.log(i) },0) } 输出了8次8,这跟js的执行顺序和作用域链有关. 规则: ...
- js中的SetTimeOut
1. SetTimeOut() 1.1 SetTimeOut()语法例子 1.2 用SetTimeOut()执行Function ...
- js循环中使用async/await踩过的坑
最近写koa的时候遇见需要在循环中使用async/await的情况,当然第一反应就是直接上forEach,然后就直接翻车了... 直接上代码: function handleSql(val) { re ...
- 深入浅出:了解for循环中保留i值得方法
一.保留i值 通常情况下,因为一些效果我们需要获取到for循环中的i的值,但是往往拿到的都是最后一个i的值.下面介绍几种方法可以获取到i的值 1.自定义属性: arr[i].index = i; 以 ...
- js的for循环中出现异步函数,回调引用的循环值总是最后一步的值?
这几天跟着视频学习node.js,碰到很多的异步函数的问题,现在将for循环中出现的异步函数回调值的问题总结如下: 具体问题是关于遍历文件夹中的子文件夹的,for循环包裹异步函数的代码: for (v ...
随机推荐
- Flask:对项目文件进行拆分
在工作中,我们不可能将ORM的配置,ORM的操作,ORM的使用以及视图放到同一个文件里,大多数时候Flask都是按照MVC的设计理念进行部署的 1.MVC和MTV (1)MVC(Model-View- ...
- Python项目生成所有依赖包的清单
最近写完的自动化脚本,分享给同事的时候发现依赖包很难解决(使用的不是virtualenv环境).想起来之前看开源接口平台项目的时候可以一键下载依赖包,于是就找到了第三方包pipreqs,可以自动帮助我 ...
- Java 发展历程
JDK 1.0 1991年4月,由 James Gosling 博士领导的绿色计划(Green Project)开始启动,此计划的目的是开发一种能够在各种消费性电子产品(如机顶盒.冰箱.收音机等)上运 ...
- 使用Beautiful Soup
Beautiful Soup初了解 # 解析工具Beautiful Soup,借助网页的结构和属性等特性来解析网页(简单的说就是python的一个HTML或XML的解析库)# Beautiful So ...
- 20190723_C的三个小实现
1. 有一个字符串开头或结尾含有n个空格(“ abcdefgdddd ”),欲去掉前后的空格,返回一个新的字符串.a) 要求1:请自己定义一个接口(函数),并实现功能:b) 要求2:编写测试 ...
- C Primer Plus (一)
摘要:重读C Primer Plus ,查漏补缺 重读C Primer Plus,记录遗漏的.未掌握的.不清楚的知识点. 一.概览 1.链接器的作用是将这3个目标元素(目标代码.系统的标准启动代码和库 ...
- 安装ubuntu16虚拟机,下载android源码,配置编译环境
Android 源码编译步骤: 我考虑了一下,目前电脑装了SSD,8G内存,使用虚拟机编译源码应该够用. 首先下载虚拟机软件,由于最近一直在使用virtualbox,感觉蛮不错了,下载地址: http ...
- NOIP的模板--考前复习
距离NOIP还有25天 可以去放弃一些巨难得题目去搞一些模板了 -------在校老师的原话 一·快排 虽然可以手打,最好用STL,里面有很多优化,会快很多 #include<iostream& ...
- python——int()、hex()、oct()、bin()、float()数值类型转换函数
摘要:在python中,数值类型转换函数常用的有浮点型float().取整int().八进制oct().二进制bin().十六进制hex()这五个函数. 单词float的意思就是浮动的意思: int是 ...
- php swoole异步处理mysql
php swoole异步处理mysql <pre>//创建websocket服务器对象,监听0.0.0.0:9509端口//异步测试$ws = new swoole_websocket_s ...