一个setTimeout问题小探索

问题

之前有提到一个异步问题,如下代码输出什么:

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++){
  let a = i;
  let p = new Promise((resolve,reject)=>{
    setTimeout(()=>{resolve(a)},1000);
  });
  p.then(i=>console.log(i))
}

思考

可能这种promise方法更麻烦了。但是适用于更复杂的需求了。假设setTimeout的时间是一个随机数。而我们要在所有数字都打印完毕再去做一些操作,那么该怎么做呢?
具体可以参见:https://segmentfault.com/a/11...

执行效率上的考虑:

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++){
  let a = i;
  let p = new Promise((resolve,reject)=>{
    setTimeout(()=>{resolve(a)},1000);
  });
  p.then(i=>console.log(i))
}
console.timeEnd('c');

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

a: 0.35009765625ms
b: 0.348876953125ms
c: 0.880126953125ms

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

总结

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

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

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

阅读 2.6k

推荐阅读
79px
用户专栏

前端开发

6 人关注
21 篇文章
专栏主页