关于JS的for循环包裹异步函数的问题

今天一个做后端的同事问了我一个JS的问题:

有个循环,循环一个异步回调,为啥回调引用的循环值都是最后一步循环的循环值?然后,又有些时候无论什么循环值都得不到?

好吧,JavaScript跟PHP的循环有时候确实不一样,JavaScript的函数有同步函数跟异步函数的区分,PHP里面没这种概念,拿PHP的常识来理解JavaScript有时候行不通。关于JS异步机制的研究,看我另一篇JS异步执行机制理解

我想了想,他说的“什么循环值也得不到的”,应该是下面这个情况:

<script type="text/javascript">
var arr = [1,3,5,7,9];
var arrLength = arr.length;

for (var i = 0; i < arrLength; i++) {
    setTimeout(function() {
        console.log(i);
        console.log(arr[i]);
    }, 2000);
}
</script>

结果是:

5
undefined
5
undefined
5
undefined
5
undefined
5
undefined

for循环有一个特点,就是“i判断失败一次才停止”。所以,i在不断的自加1的时候,直到i等于5,i才失败,这时候循环体不再执行,会跳出,所以i等于5没错。那么为什么5次循环的i都等于5?原因就是setTimeout()的回调,也就是console.log(i);console.log(arr[i]);被压到任务队列的最后,for循环是同步任务,所以先执行,等于是空跑了5次循环。于是,i都等于5之后,console.log(i);console.log(arr[i]);刚开始第一次执行,当然输出全是5。

然后,同事说,有时候JS的for循环,永远只得到最后一个循环值,那其实他用的是for...in...循环。具体不多解释了。

我既然听了他的问题,就要给他解决方案。

我先建议他用自执行函数传参,这样自执行函数内部形成了局部作用域,不受外部变量变化的影响。范例代码是:

<script type="text/javascript">
var arr = [1,3,5,7,9];
var arrLength = arr.length;

for (var i = 0; i < arrLength; i++) {
    (function(i) {
        setTimeout(function() {
            console.log('i是' + i);
            console.log('value是' + arr[i]);
        }, 2000);
    })(i);
}
</script>

得到:

Paste_Image.png

不但解决了undefined的问题,而且解决了异步函数传参的问题。

然后我把范例代码给了他。然而,他的JS代码写的太乱,拿这个例子改居然改不对。于是我又给了一个jQuery方案给他:

<script type="text/javascript">
var arr = [1,3,5,7,9];

$.each(arr, function(key, value) {
    setTimeout(function() {
        console.log('i是' + key);
        console.log('value是' + value);
    }, 2000);
});
</script>

用jQuery的$.each(),自带回调函数,形成了函数作用域,这娃最终解决了问题。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式。简单...
    舟渔行舟阅读 7,842评论 2 17
  • 弄懂js异步 讲异步之前,我们必须掌握一个基础知识-event-loop。 我们知道JavaScript的一大特点...
    DCbryant阅读 2,750评论 0 5
  • topics: 1.The Node.js philosophy 2.The reactor pattern 3....
    宫若石阅读 1,126评论 0 1
  • Node.js是目前非常火热的技术,但是它的诞生经历却很奇特。 众所周知,在Netscape设计出JavaScri...
    w_zhuan阅读 3,641评论 2 41
  • 单例模式 适用场景:可能会在场景中使用到对象,但只有一个实例,加载时并不主动创建,需要时才创建 最常见的单例模式,...
    Obeing阅读 2,103评论 1 10