循环中的异步&&循环中的闭包

原文链接
在这之前先要相识一下

for轮回中let 和var的区分

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

    function foo() {
      for (var index = 0; index < array.length; index++) {
        //..轮回中的逻辑代码
      }
      console.log(index);//=>5
    }
    foo()
   console.log(index)//Uncaught ReferenceError: index is not defined

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

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

报错了,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()

看下输出
《循环中的异步&&循环中的闭包》
关于let的

    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,这是一个异步,这就是我们本日要议论的

轮回中的异步

setTimeout(func,time)函数运转机制

setTimeout(func,time)是在time(毫秒单元)时候后实行func函数。浏览器引擎按递次实行顺序,碰到setTimeout会将func函数放到实行行列中,比及主顺序实行终了以后,才最先从实行行列(行列中能够有多个待实行的func函数)中根据time延时时候的先后递次取出来func并实行。纵然time=0,也会等主顺序运转完以后,才会实行。

一个需求,一个数组array[1,2,3,4,5],轮回打印,距离1秒

上面的let是轮回打印了12345,然则不是距离1s打印的,是在foo函数实行1s后,同时打印的

体式格局一 摒弃for轮回,运用setInterval

    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()

我们上面说到,当for轮回碰到了var,变量index的作用域在foo函数下,轮回一次赋值一次,5次轮回完成,index末了的效果赋值就为5;就是被终究赋值的index,就是5;

体式格局二,引入全局变量

代码实行递次是,先同步实行for轮回,再实行异步行列,在for轮回实行终了后,异步行列最先实行之前,index经由for轮回的处置惩罚,变成了5。
所以我们引入一个全局变量j,使j在for轮回实行终了后,异步行列最先实行之前,依然是0,在异步实行时举行累加

    var j = 0;
    for (var index = 0; index < array.length; index++) {
      setTimeout(() => {
        console.log(j);
        j++;
      }, 1000 * index)
    }

体式格局三 for轮回合营setTimeout(通例思绪,不赘述,口试必备妙技)

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

体式格局四,经由过程闭包完成

最先议论体式格局四之前我引荐先浏览一遍我之前写过一篇文章
谈一谈javascript作用域
我们对上面的题目再次剖析,for轮回同步实行,在for轮回内部碰到了setTimeout,setTimeout是异步实行的,所以加入了异步行列,当同步的for轮回实行终了后,再去实行异步行列,setTimeout中有唯一的一个参数数index
体式格局三可行,是由于let是块级作用域,每次for实行都邑建立新的变量index,for轮回实行终了后,异步实行之前,建立了5个自力的作用域,5个index变量,分别是0,1,2,3,4,互相自力,互不影响,输出了预期的效果
如果说每次轮回都邑天生一个自力的作用域用来保留index,题目就会得到解决,所以,我们经由过程闭包来完成

    const array = [1, 2, 3, 4, 5]

    function foo() {
      for (var index = 0; index < array.length; index++) {
        function fun(j) {
          setTimeout(function () {
            console.log(j);
          }, 1000 * j);
        }
        fun(index)
      }
    }
    foo()

setTimeout中的匿名回调函数中引用了函数fun中的局部变量j,所以当fun实行终了后,变量j不会被开释,这就形成了闭包
固然我们能够对此举行一下优化

    const array = [1, 2, 3, 4, 5]

    function foo() {
      for (var index = 0; index < array.length; index++) {
        (function(j) {
          setTimeout(function () {
            console.log(j);
          }, 1000 * j);
        })(index)
      }
    }
    foo()

将foo函数改成匿名的马上实行函数,效果是雷同的

总结

for轮回自身是同步实行的,当在for轮回中碰到了异步逻辑,异步就会进入异步行列,当for轮回实行完毕后,才会实行异步行列
当异步函数依靠于for轮回中的索引时(一定是存在依靠关联的,不然不会再轮回中变更异步函数)要斟酌作用域的题目,
在ES6中运用let是最好的挑选,
当运用var时,能够斟酌再引入一个索引来替换for轮回中的索引,新的索引逻辑要在异步中处置惩罚
也能够运用闭包,模仿完成let
在现实开辟过程当中,轮回挪用异步函数,比demo要庞杂,能够还会涌现if和else推断等逻辑,详细的我们下次再续

参考
经由过程for轮回每隔两秒按递次打印出arr中的数字
setTimeOut和闭包
《你不知道的JavaScript》上卷

    原文作者:陌上寒
    原文地址: https://segmentfault.com/a/1190000018369858
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞