• 浅谈循环中setTimeout执行顺序问题


    浅谈循环中setTimeout执行顺序问题

    (下面有见解一二)

    期望:开始输出一个0,然后每隔一秒依次输出1,2,3,4。

    for (var i = 0; i < 5; i++) {
    setTimeout(function() {
    console.log(i);
    }, 1000 * i);
    }

     结果:输出5。

    原因:setTimeout 使函数延迟1s执行,而for循环执行完成还不到0.1秒,到执行函数的时候,其实 i 已经变成5了,因此console.log(i)输出5。

    解决方法一:使用let块作用域。 

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


    解决方法二:加个闭包。

    for (var i = 0; i < 5; i++) {
    (function(i) {
    setTimeout(function() {
    console.log(i);
    }, 1000 * i);
    })(i);
    

    结果:开始输出一个0,然后每隔一秒依次输出1,2,3,4。

    失败方法: 

    for (var i = 0; i < 5; i++) {
    (function() {
    setTimeout(function() {
    console.log(i);
    }, 1000 * i);
    })();
    }

    结果:输出 5。

    原因:去掉函数的参数i,则函数内部没有对i保持引用。

    解决方法三:

    for (var i = 0; i < 5; i++) {
    setTimeout((function(i) {
    console.log(i);
    })(i), i * 1000);
    }

    结果:立马输出0-4。

    原因:setTimeout可以接受函数或者字符串作为参数,而给setTimeout传递了一个立即执行函数,该立即执行函数是undefined ,也就是说等价于setTimeout(undefined, ...)。立即执行函数会立即执行。

     见解一:

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

    setTimeout是异步执行的,1000毫秒后向任务队列里添加一个任务,只有主线上的全部执行完才会执行任务队列里的任务,所以当主线程for循环执行完之后 i 的值为5,这个时候再去任务队列中执行任务,i全部为5;

    每次for循环的时候setTimeout都会执行,但是里面的function则不会执行被放入任务队列,因此放了5次;for循环的5次执行完之后不到1000毫秒;

    1000毫秒后全部执行任务队列中的函数,所以就是输出五个5啦

    假如把var换成let,那么输出结果为0,1,2,3,4;

    因为let  i  的是区块变量,每个i只能存活到大括号结束,并不会把后面的for循环的  i  值赋给前面的setTimeout中的i;而var i  则是局部变量,这个 i 的生命周期不受for循环的大括号限制;

    见解二:

    for(var i=0;i<=3;i++){

      setTimeout(function() {  

        console.log(i)  

      }, 10);

    }

    答案:打印4次4

    这道题涉及了异步、作用域、闭包

    settimeout是异步执行,10ms后往任务队列里面添加一个任务,只有主线上的全部执行完,才会执行任务队列里的任务,当主线执行完成后,i是4,所以此时再去执行任务队列里的任务时,i全部是4了。对于打印4次是:

     每一次for循环的时候,settimeout都执行一次,但是里面的函数没有被执行,而是被放到了任务队列里面,等待执行,for循环了4次,就放了4次,当主线程执行完成后,才进入任务队列里面执行。
       (注意:for循环从开始到结束的过程,需要维持几微秒或几毫秒。)
    当我把var 变成let 时
    for(let i=0;i<=3;i++){ setTimeout(function() {  console.log(i)  }, 10);}
    打印出的是:0,1,2,3
    当解决变量作用域,

    因为for循环头部的let不仅将i绑定到for循环快中,事实上它将其重新绑定到循环体的每一次迭代中,确保上一次迭代结束的值重新被赋值。setTimeout里面的function()属于一个新的域,通过 var 定义的变量是无法传入到这个函数执行域中的,通过使用 let 来声明块变量,这时候变量就能作用于这个块,所以 function就能使用 i 这个变量了;这个匿名函数的参数作用域 和 for参数的作用域 不一样,是利用了这一点来完成的。这个匿名函数的作用域有点类似类的属性,是可以被内层方法使用的。

    查了一下百度的一个答案:

    setTimeout是一次执行函数,这里是10ms后执行,仅仅执行一次;for(var i=0;i<=3;i++),i的每次取值都是执行setTimeout这个函数,并没有执行setTimeout里面的function(即闭包函数),setTimeout里面的function是有setTimeout的定时触动的,也就是10ms后执行,也就是说i从0~3时,一共执行了4次的setTimeout()函数,此时的i的值是4,由于for语句的执行速度远小于1秒,所以,1秒后,由setTimeout()函数定时触动的闭包函数function()开始执行,alert(i);i的值已经是4了,所以相继打印4次i.


    ---------------------
    原文:https://blog.csdn.net/huakaiwuxing/article/details/78968642 

  • 相关阅读:
    SpringKafka——消息监听
    RabbitMQ(八)线程池消费
    RabbitMQ(七)延迟队列
    window计划任务 0x1
    获取网页URL地址及参数等的两种方法(js和C#)
    HttpWebRequest的偶尔请求超时问题
    用HTML、CSS、JS制作圆形进度条(无动画效果)
    批量关联update
    仅仅 IE8 有效的 CSS hack 写法
    SqlServer关闭与启用标识(自增长)列
  • 原文地址:https://www.cnblogs.com/Antwan-Dmy/p/10691885.html
Copyright © 2020-2023  润新知