for循环中嵌套setTimeout,执行顺序和结果该如何理解?

这两天在捣鼓做用域的问题,有的时候知识这个东西真的有点像是牵一发而动全身的感受。在理解做用域的时候,又看到了一道经典的面试题和例子题。面试

那就是在for循环中嵌套setTimeout延时,想一想以前面试的时候面试官问到我这个问题,然而我当时对这玩意儿根本没有深究,没有去理解;很是草率的回答了,面试官好心的给我异步

说这个涉及到setTimeout回调函数异步特性,啪啦啪啦,说的好几句都感受晕乎了~也感受JS这个东西真的须要深刻的东西还不少,路也还很长。函数

直接进入主题了,先贴一段简单的代码:学习

结果是10次10。不得不说看到答案的第一眼真的魔怔啊,彻底不理解为何是10次10;只有你多去了解JS的执行机制以后,或许心中就有答案了。因此如下是我我的在看了众多的线程

网上的各位高手的看法以后,总结如下获得的一个看法。若有歧义,欢迎各位的指正。3d

     首先这样的结果须要从JS的执行机制提及。JS是单线程环境,也就是说代码的执行是从上到下,依次执行。这样的执行称为同步执行。由于种种不要浪费和节约的缘由。JS中引进了异步的机制。在这段代码中,哪一个是同步哪一个是异步呢?for循环是同步代码,而setTimeout中的是异步代码。那么JS碰到这个有同步和异步的状况下会先从上到下执行同步代码,碰到异步的代码会将其插入到任务队列当中等待。而setTimeout是延时,也就是说碰到setTimeout这个异步的代码块会根据它里面的第二个参数:延时时间来将代码插入到任务队列当中,好比上面这段代码中,第二个参数延时时间是0,也就是说执行到它的时候会在0ms以后将它插入到任务队列当中。同步代码都执行完成以后,那么JS引擎就空闲了,这个时候就轮到任务队列中的异步代码依次加载了。blog

这是上面这段代码的答案的一半。另外一半就来自于做用域,做用域是变量等资源的做用范围。在这段代码中准确的说是做用域链的问题,当同步代码执行完毕开始执行异步的setTimeout代码时,setTimeout中须要一个变量 ---i---,而执行的时候在当前的做用域中开始找,找不到变量i的定义,这个时候就把建立这个函数的做用域做为当前做用域,再次寻找,建立这个函数的做用域就是全局做用域,也就是找到了for循环中i,找到了以后就结束寻找变量i的行程。因为这个时候的i是全局的,并且人家已经变为了最终形态:10,setTimeout找到的就是这个i=10;因此就输出了10,下面的9次setTimeout 的执行都是相似,因此结果都是10;队列

因此我对这个答案的理解归结起来就是  异步加载+做用域链。可见要理解一段看似简单的代码,要去学习的东西还真很多。资源

问题出来了,相应的就有解决方案;对于这类问题比较常见的解决方法就是 当即执行函数。它逼迫js每次循环进来的时候都会当即去执行代码,从而保证了每一次获得了i的副本都是不同的。贴代码:作用域

如上图,获得了想要的答案

相关文章
相关标签/搜索