关于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 ...
随机推荐
- 一篇文章让你彻底理解java中抽象类和接口
目录 1.我所理解的抽象类 2.我所理解的接口 3.抽象类和接口本质区别 相信大家都有这种感觉:抽象类与接口这两者有太多相似的地方,又有太多不同的地方.往往这二者可以让初学者摸不着头脑,无论是在实际编 ...
- Java 计算n对应的二进制位上有几个1,分别在什么位置
Java计算n的二进制位上有几个1,分别在什么位置 public List<Integer> getBinOneCount(int n){ List<Integer> ...
- 学习笔记14Js使用技巧
**页面加载完毕时执行一段代码$(fuction(){ initialMethod(); }); *将一个<form>序列化为json对象并传给服务器var postData = $(&q ...
- cdq分治 陌上花开(内无题解)
由于有归并排序 要注意是对原来的那个元素进行更新答案和删除操作 而不是占据原来那个元素下标的元素
- 4、Hibernate的查询方式
一.Hibernate的查询方式:OID查询 1.OID检索:Hibernate根据对象的OID(主键)进行检索 1-1.使用get方法 Customer customer = session.get ...
- 七月月赛T2
题目描述 “X龙珠”是一款益智小游戏.游戏中有 n(2∣n) 个编号互不相同龙珠按照给定的顺序排成一个队列,每个龙珠上面都有一个编号.每次操作时,选择并取出龙珠队列中相邻的两个龙珠,放到目标队列的末尾 ...
- Project Euler 56: Powerful digit sum
一个古戈尔也就是\(10^{100}\)是一个天文数字,一后面跟着一百个零.\(100^{100}\)更是难以想像的大,一后面跟着两百个零.但是尽管这个数字很大,它们各位数字的和却只等于一.考虑两个自 ...
- python——namedtuple
namedtuple()概念理解分享 我们都知道元组tuple的概念,tuple是一个定义之后就不能够更改的可迭代对象,namedtuple作为tuple的兄弟具有同样的属性,一旦定义就不可以更改.但 ...
- 008.Kubernetes二进制部署Nginx实现高可用
一 Nginx代理实现kube-apiserver高可用 1.1 Nginx实现高可用 基于 nginx 代理的 kube-apiserver 高可用方案. 控制节点的 kube-controller ...
- 创建一个线程池(java)
private ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("billService-poo ...