美文网首页
for循环中嵌套setTimeout,执行顺序和结果的理解

for循环中嵌套setTimeout,执行顺序和结果的理解

作者: AMONTOP | 来源:发表于2019-01-11 15:59 被阅读0次
    for(var i=0;i<10;i++){
        setTimeout(function () {
            console.log(i);
        },0)
    }
    

    同步优先、异步靠边、回调垫底!
    公式表达:同步 => 异步 => 回调

    JS是单线程环境,也就是说代码的执行是

    同步执行:从上到下,依次执行。

    for循环是同步代码,setTimeout中的是异步代码。

    那么JS碰到这个有同步和异步的情况下:

    • ①会先从上到下执行同步代码
    • ②碰到异步的代码会将其插入到任务队列当中等待。
    • ③setTimeout是延时,碰到setTimeout这个异步的代码块会根据它里面的第二个参数,延时时间来将代码插入到任务队列当中

    比如上面这段代码中,第二个参数延时时间是0,也就是说执行到它的时候会在0ms之后将它插入到任务队列当中。
    同步代码都执行完成之后,那么JS引擎就空闲了,这个时候就轮到任务队列中的异步代码依次加载了。

    这是上面这段代码的答案的一半。


    另一半就来自于作用域,作用域是变量等资源的作用范围。
    在这段代码中准确的说是作用域链的问题,当同步代码执行完毕开始执行异步的setTimeout代码时,

    • 1.setTimeout中需要一个变量 i,
    • 2.而执行的时候在当前的作用域中开始,找不到变量i的定义,
    • 3.这个时候就把创建这个函数的作用域作为当前作用域,再次寻找,创建这个函数的作用域就是全局作用域,
    • 4.也就是找到了for循环中i,找到了之后就结束寻找变量i的行程。
      由于这个时候的i是全局的,而且人家已经变为了最终形态:10,
      setTimeout找到的就是这个i=10;所以就输出了10,下面的9次setTimeout 的执行都是类似,所以结果都是10;

    解决方法:

    1、立即执行函数
    它逼迫js每次循环进来的时候都会立即去执行代码,从而保证了每一次得到了i的副本都是不一样的。

    for(var i=0;i<10;i++){
            (function (e) {
                setTimeout(function () {
                    console.log(e);
                }, 0);
            })(i)
        }
    

    2、let

    for (let i = 0; i < 10; ++i) {  
        setTimeout(function() {  
            console.log(i);  
        }, 1000);  
    } 
    

    相关文章

      网友评论

          本文标题:for循环中嵌套setTimeout,执行顺序和结果的理解

          本文链接:https://www.haomeiwen.com/subject/prybrqtx.html