V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
wesleypursuit
V2EX  ›  前端开发

一个 setTimeout 问题小探索

  •  
  •   wesleypursuit · 2016-09-13 11:16:57 +08:00 · 2121 次点击
    这是一个创建于 2783 天前的主题,其中的信息可能已经有所发展或是发生改变。

    问题

    之前有提到一个异步问题,如下代码输出什么: for(var i = 0;i<10;i++){ setTimeout(function(){ console.log(i);
    },1000); } 这是我近期遇到的一个面题。当时我并不知道。不过后来面试官告诉我, setTimeout 是异步执行的。并且告诉了我答案。后来在群里边讨论,明白了。会输出 10 个 10 。

    探索

    为什么呢?首先, setTimeout 是异步执行的。所以在 setTimeout 执行之前,全局变量 i 早就已经变成了 10 。

    那么如何解决能让他输出 0-9 呢?其实要解决的就是:在使用 i 的时候保证 i 的值还是我们当时希望的那个值。

    如果不考虑兼容性,我们可以使用 es6 的 let ,把每个 i 变成一个局部变量。代码如下: for(let i = 0;i<10;i++){ setTimeout(function(){ console.log(i);
    },1000); } 如果要考虑兼容性,那么我们用一个匿名函数,把 i 当做参数传进去,这样我们再用的 i 就是局部变量了。不会受到外边的影响了。代码如下:

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

    如果使用 promise ,那么我们可以使用如下写法:

    for(var i = 0;i<10;i++){
      new Promise((resolve,reject)=>{
        setTimeout(resolve(console.log(i)),1000);
      });
    }
    

    执行效率上的考虑:

    console.time('a');
    for(let i = 0;i<10;i++){
      setTimeout(function(){
        console.log(i);  
      },1000);
    }
    console.timeEnd('a');
    console.time('b');
    for(var i = 0;i<10;i++){
      (function(i){
        setTimeout(function(){
          console.log(i);  
        },1000);
      })(i)
    }
    console.timeEnd('b');
    console.time('c');
    for(var i = 0;i<10;i++){
      new Promise((resolve,reject)=>{
        setTimeout(resolve(console.log(i)),1000);
      });
    }
    console.timeEnd('c');
    

    效率上,我在目前新版 chrome 的执行结果如下:

    a: 0.228ms
    b: 0.203ms
    c: 5.863ms
    

    注意:可能不同系统不同环境的执行结果不一样。所以,有时候极客玩玩就是了,认真你就输啦-.-

    总结

    以前我偏执的认为,能做出东西就行了。基础不重要。所以我总是一只停留在做东西的阶段。但是后来反过来想:假设你想买车,那么你会选一个对汽车参数很熟的销售员还是选择一个你问什么问题他都说查查再回答你的销售员呢?答案是肯定的。所以说,可能公司招人也一样吧。

    但是,这些问题真的有用吗?没错,我都有很多问题没回答好,如果是为了准备一次很 nice 的面试,我大可以特意的多跑几家,然后把遇到的有问题的面试题都总结下来。不会的再去查询,我想翻来覆去也没多少基础可问吧?就像找个美工就问:你会切图嘛?这些稍微花点时间都能学会的问题。个人觉得没特别大的意义。

    (本文摘取自我的博客: http://79px.com/blog/57cd347be61eaab312faec27

    11 条回复    2016-09-14 14:27:41 +08:00
    ChiangDi
        1
    ChiangDi  
       2016-09-13 11:32:12 +08:00 via Android
    这个问题比学会切图简单太多了
    jiongxiaobu
        2
    jiongxiaobu  
       2016-09-13 12:17:20 +08:00 via iPhone
    好厉害啊 能写出那么多字
    ericls
        3
    ericls  
       2016-09-13 12:19:15 +08:00 via iPhone
    了解 call stack 即可!
    xcodebuild
        4
    xcodebuild  
       2016-09-13 13:21:02 +08:00 via Android
    因为 var 是函数作用域的原因
    j4fun
        5
    j4fun  
       2016-09-13 13:53:26 +08:00
    setTimeout 主要不是用在这种地方的。。主要是用在需要同步转异步的地方,可以用 setTimeout(func(){...}, 0) 好几年不写 js 了><,感觉这个变的好快,有时候看新的标准都有点看不懂了~
    learnshare
        6
    learnshare  
       2016-09-13 13:59:52 +08:00
    并不是说没有用,写的时候一般都坑了自己。
    zi
        7
    zi  
       2016-09-13 14:08:33 +08:00
    第一个用闭包就好了
    for(var i = 0;i<10;i++){
    setTimeout(function(i){
    console.log(i);
    }(i),1000);
    }
    YuJianrong
        8
    YuJianrong  
       2016-09-14 10:30:03 +08:00   ❤️ 1
    喂喂,这“探索”都出错了啊,先整理下自己的思路吧。

    Promise 那个,

    for(var i = 0;i<10;i++){
    new Promise((resolve,reject)=>{
    setTimeout(resolve(console.log(i)),5000);
    });
    }

    因为 Promise 没有被使用,所以 Promise 的 func 直接运行, resolve 的返回值是 undefined, 所以 setTimeout 相当于 call 了
    setTimeout(undefined, 1000);

    所以总的来说这代码等价于:

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

    LZ 你还要好好学学 Promise 怎么工作啊……
    YuJianrong
        9
    YuJianrong  
       2016-09-14 10:30:53 +08:00
    @zi 你这个错误和我上面说的一样。
    zi
        10
    zi  
       2016-09-14 10:46:17 +08:00
    @YuJianrong 这错误我又犯了。。
    这才对。。这样的话跟楼主第二个一样
    setTimeout(function(i){
    return function(){
    console.log(i);
    };
    }(i),1000);
    wesleypursuit
        11
    wesleypursuit  
    OP
       2016-09-14 14:27:41 +08:00
    @YuJianrong 好吧,感谢提醒。 promise 本来不是很熟 这个写法是我写完博客后又有群友提供的,当时也有怀疑。但是只执行了下看结果是对的就贴上了。这么解释下就明白了-.-
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2805 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 06:03 · PVG 14:03 · LAX 23:03 · JFK 02:03
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.