关于for循环中使用setTimeout的四种解决方案

来源:http://www.chinese-glasses.com 作者:Web前端 人气:200 发布时间:2020-03-14
摘要:时间: 2019-12-04阅读: 89标签: 循环 时间: 2019-03-04阅读: 503标签: 闭包for循环中let 和var的区别 我们先来简单了解一下setTimeout延时器的运行机制。setTimeout会先将回调函数放到等待队列中,等

时间: 2019-12-04阅读: 89标签: 循环

时间: 2019-03-04阅读: 503标签: 闭包for循环中let 和var的区别

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

var 是函数级作用域或者全局作用域,let是块级作用域看一个例子

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

 function foo() { for (var index = 0; index  array.length; index++) { //..循环中的逻辑代码 } console.log(index);//=5 } foo() console.log(index)//Uncaught ReferenceError: index is not defined
for (var i=1; i=5; i++) { setTimeout( function timer() { console.log( i ); }, i*1000 );}

foo函数下的index输出5,全局下的index不存在现在我们把var 换为let

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

 function foo() { for (let index = 0; index  array.length; index++) { //..循环中的逻辑代码 } console.log(index)//Uncaught ReferenceError: index is not defined } foo()

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

报错了,index不在foo函数作用域下,当然肯定也不会再全局下因为var和let的这个区别(当然var和let的区别不止于此)所以导致了下面的这个问题关于var的

我们来看另一种情况:

 const array = [1, 2, 3, 4, 5] function foo() { for (var index = 0; index  array.length; index++) { setTimeout(() = { console.log(index); }, 1000); } } foo()
for (var i=1; i=5; i++) { (function() { setTimeout( function timer() { console.log( i ); }, i*1000 ); })();}

关于let的

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

 const array = [1, 2, 3, 4, 5] function foo() { for (let index = 0; index  array.length; index++) { setTimeout(() = { console.log(index); }, 1000); } } foo()

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

因为var和let 在作用域上的差别,所以到这了上面的问题使用var 定义变量的时候,作用域是在foo函数下,在for循环外部,在整个循环中是全局的,每一次的循环实际上是为index赋值,循环一次赋值一次,5次循环完成,index最后的结果赋值就为5;就是被最终赋值的index,就是5;let的作用局的块级作用局,index的作用域在for循环内部,即每次循环的index的作用域就是本次循环,下一次循环重新定义变量index;所以index每次循环的输出都不同这里还有另外一个问题,setTimeout,这是一个异步,这就是我们今天要讨论的

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

循环中的异步setTimeout(func,time)函数运行机制

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

setTimeout(func,time)是在time(毫秒单位)时间后执行func函数。浏览器引擎按顺序执行程序,遇到setTimeout会将func函数放到执行队列中,等到主程序执行完毕之后,才开始从执行队列(队列中可能有多个待执行的func函数)中按照time延时时间的先后顺序取出来func并执行。即使time=0,也会等主程序运行完之后,才会执行。

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

一个需求,一个数组array[1,2,3,4,5],循环打印,间隔1秒

解决方案2:拆分结构

上面的let是循环打印了12345,但是不是间隔1s打印的,是在foo函数执行1s后,同时打印的

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

方式一 放弃for循环,使用setInterval

function timer(i) { setTimeout( console.log( i ), i*1000 );}for (var i=1; i=5;i++) { timer(i);}
 function foo(){ let index = 0; const array = [1, 2, 3, 4, 5] const t = setInterval(()={ if (index  array.length) { console.log(array[index]); } index++; }, 1000); if (index = array.length) { clearInterval(t); } } foo()

本文由10bet发布于Web前端,转载请注明出处:关于for循环中使用setTimeout的四种解决方案

关键词:

最火资讯