js经典面试问题:如何让for循环中的setTimeout()函数像预想中一样工作?

可能经常有人碰到类似下面的这种情况:

for (var i = 1; i <= 2; i++) {
    setTimeout(function() { alert(i) }, 100);
}

跑起来后,alert的两次内容都是数字3,而不是自己所期望的先1后2。有一种基础面试题是,如何合理改动代码,使它返回期望的结果?

其实很简单。在stackoverflow上早有大神解释了,可以参考这个链接

答案翻译成中文如下(并做了部分修改方便理解):

---------------------------------------------------------------------------------

你要为每个定时器处理函数创建不同的“i”变量副本。比如这样:

function doSetTimeout(i) {
  setTimeout(function() { alert(i); }, 100);
}

for (var i = 1; i <= 2; ++i)
  doSetTimeout(i);

如果你不做这样的事情 (这种方法在实际上也会有其他变种),每个定时器处理函数就会共享同一作用域里的同一变量"i"。当循环完成时的"i"是多少?是3!这里通过定义一个函数来实现中介的作用,从而创建了变量的值的副本。由于setTimeout()是在该副本的上下文中调用的,所以它每次都有自己的私有的"i"以供使用。

但是随着时间的推移,这些代码的效果显得有些混乱是显而易见的事实,因为设立一些时间间隔相同的连续的setTimeout()将导致所有延时处理程序同时被调用。了解设置timer(对setTimeout()的调用)几乎不消耗时间是很重要的。也就是说,告诉系统“请在1000毫秒后调用此函数”将会被立即返回,因为在timer队列中安装延时请求的过程非常快。

因此,如果有一串连续的延时请求(比如我答案中的代码),而且每一个时间延迟值是相同的,那么一旦经过足够的时间,所有延时处理程序将一个接一个快速连续调用。

如果你需要的是在固定时间间隔调用的处理程序,你可以使用setInterval(),行为非常类似setTimeout(),但每经过一定时间就运行一次。或者你可以调用以“时间值乘以迭代计数器”为时间间隔的setTimeout。也就是说,修改我刚才的示例代码:

function doScaledTimeout(i) {
  setTimeout(function() {
    alert(i);
  }, i * 5000);
}

(100毫秒超时,效果不会很明显,所以我设置的数字高达5000)

“i”值乘以基础延迟值,所以循环5次将导致分别延迟5秒,10秒,15秒,20秒,和25秒。

时间: 2024-10-13 13:00:06

js经典面试问题:如何让for循环中的setTimeout()函数像预想中一样工作?的相关文章

js setTimeout函数

最近在看JS DOM编程艺术,在第十章的动画里面有个setTimeout函数的例子中涉及了很多的引号,研究了好大一会才看明白,综合网上各个大神的解释和自己的理解,其原理是这样的: 首先看下程序源代码: 1 function moveElement(elementID,final_X,final_Y,interval){ 2 if(!document.getElementById) return false; 3 if(!document.getElementById(elementID)) re

js面向对象面试资料

js面向对象面试资料 1 说说你对闭包的理解 使用闭包主要是为了设计私有的方法和变量.闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露. 闭包有三个特性: 1.函数嵌套函数 2.函数内部可以引用外部的参数和变量 3.参数和变量不会被垃圾回收机制回收 2.call() 和 .apply() 的区别和作用? 作用:动态改变某个类的某个方法的运行环境. 1.call,apply都属于Function.prototype的一个方法,它是JavaScr

Linux驱动经典面试题目

1.  linux驱动分类 2.  信号量与自旋锁 3.  platform总线设备及总线设备如何编写 4.  kmalloc和vmalloc的区别 5.  module_init的级别 6.  添加驱动 7.  IIC原理,总线框架,设备编写方法,i2c_msg 8.  kernel panic 9.  USB总线,USB传输种类,urb等 10.android boot 流程 11.android init解析init.rcLinux驱动经典面试题目,布布扣,bubuko.com

C语言经典面试题目(转的,不过写的的确好!)

第一部分:基本概念及其它问答题 1.关键字static的作用是什么? 这个简单的问题很少有人能回答完全.在C语言中,关键字static有三个明显的作用: 1). 在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变. 2). 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问.它是一个本地的全局变量. 3). 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用.那就是,这个函数被限制在声明它的模块的本地范围内使用. 大多

JS经典拼板游戏

原文链接:http://www.guimigame.com/thread-49-1-1.html,对于代码有什么不明白的地方,可以到这里给我发问哦! 效果演示 废话不多说了,直接上代码! <!doctype html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>JS重现

【前端】Vue.js经典开源项目汇总

Vue.js经典开源项目汇总 原文链接:http://www.cnblogs.com/huyong/p/6517949.html Vue是什么? Vue.js(读音 /vju?/, 类似于 view) 是一套构建用户界面的 渐进式框架.与其他重量级框架不同的是,Vue 采用自底向上增量开发的设计.Vue 的核心库只关注视图层,并且非常容易学习,非常容易与其它库或已有项目整合.另一方面,Vue 完全有能力驱动采用单文件组件和 Vue 生态系统支持的库开发的复杂单页应用. Vue.js 的目标是通过

JS常见面试题目 选择的第几个radio,name一样都叫radiogroup

<html> <head> <script language="javascript"> function parse() { } </script> </head> <body> <form onsubmit = "return parse()"> <input name="radioGroup" type="radio"/> &

Vue.js经典开源项目汇总

Vue.js经典开源项目汇总 原文链接:http://www.cnblogs.com/huyong/p/6517949.html Vue是什么? Vue.js(读音 /vju?/, 类似于 view) 是一套构建用户界面的 渐进式框架.与其他重量级框架不同的是,Vue 采用自底向上增量开发的设计.Vue 的核心库只关注视图层,并且非常容易学习,非常容易与其它库或已有项目整合.另一方面,Vue 完全有能力驱动采用单文件组件和 Vue 生态系统支持的库开发的复杂单页应用. Vue.js 的目标是通过

JS经典算法

JS经典算法: // 1.字符串颠倒 str.split('').reverse().join('') // 2.不借助中间量,颠倒a.b a=[b,b=a][0] // 3.快速获取数组的最大值.最小值 Array.prototype.max = function () { return Math.max.apply(null, this) } Array.prototype.min = function () { return Math.min.apply(null, this) } //