美文网首页
你不知道的JavaScript -- setTimeout

你不知道的JavaScript -- setTimeout

作者: 华戈的小书 | 来源:发表于2020-07-12 16:08 被阅读0次

    谈起setTimeout,就让我想起了一道经典的前端面试题

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

    看到这几行代码,看过类似题目的大家肯定都知道结果是输出5个6,
    这是由于i变量声明在全局,导致只有一个全局作用域里面只有一个i变量,所以i变量的变化值没有地方存储。

    解决办法大家估计也清楚,简单的介绍2种:
    1、立即执行函数

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

    2、块级作用域

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

    为什么会输出5个6呢?

    前面说的只是很简单的一方面原因,真正涉及的核心是javaScript的单线程特性。

    JavaScript设计的初衷,是浏览器用来与用户进行交互和DOM操作的。这就决定了它必须是单线程的,设想JavaScript同事有两个线程,一个线程在DOM节点添加内容,一个线程删除该节点,浏览器就会出现混乱。所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。

    单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。

    为了优化单线程的性能,JavaScript将任务分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有主线程中的同步任务执行完毕,异步任务才会进入执行队列执行。只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。这个过程会不断重复。

    这样我们就可以很好地理解为什么会输出5个6了,由于setTimeout的执行是异步任务,所以放在任务队列中等待执行,for循环执行完之后,全局作用域的变量i此时已经变成了6,异步任务开始执行,去获取变量i只能得到6,所以最后输出的结果就是5个6了。
    如果想方便理解的话,把过程简化成等效的同步代码如下:

    for(var i = 1; i <= 5; i ++) {}
    setTimeout(function time() { console.log(i);}, 1000); // 6
    setTimeout(function time() { console.log(i);}, 1000); // 6
    setTimeout(function time() { console.log(i);}, 1000); // 6
    setTimeout(function time() { console.log(i);}, 1000); // 6
    setTimeout(function time() { console.log(i);}, 1000); // 6
    

    最后给一个简单题目看看结果是什么?

        setTimeout(function(){while(true){ console.log(0)}},1300);
        setTimeout(function(){console.log(1)},1600);
        setTimeout(function(){console.log(2)},1000);
    

    是不是想着最开始输出2,0,1呢?

    其实结果不是输出2,0,1。

    控制台执行下,那么结果是2,0,0......,一个完美的死循环。
    所以别只关注定时器的问题,忽略了while语句了。

    相关文章

      网友评论

          本文标题:你不知道的JavaScript -- setTimeout

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