for循环 + setTimeout 结合一些示例(前端面试题)


Posted in Javascript onAugust 30, 2017

一、背景

最近在翻看以前的老书《node.js开发指南》,恰好碰到 for 循环 + setTimeout 的经典例子,于是重新梳理了思路并记录下。

二、写在前面,setTimeout 和 setInterval 的执行机制

在日常编码中,你会发现,给 setTimeout 和 setInterval 设定延迟时间往往并不准,或者干脆 setTimeout(function(){xxx},0) 也不是立马执行(特别是有耗时代码在前),这是因为 js 是单线程的,有一个事件队列机制,setTimeout 和 setInterval 的回调会到了延迟时间塞入事件队列中,排队执行。

setTimeout :延时 delay 毫秒之后,啥也不管,直接将回调函数加入事件队列。

setInterval :延时 delay 毫秒之后,先看看事件队列中是否存在还没有执行的回调函数( setInterval 的回调函数),如果存在,就不要再往事件队列里加入回调函数了。

看下面示例:

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

结果:1 秒之后,同时输出 5 个 5。

因为 for 循环会先执行完(同步优先于异步优先于回调),这时五个 setTimeout 的回调全部塞入了事件队列中,然后 1 秒后一起执行了。

三、正文

接下来就是那道经典的代码:

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

结果:5 5 5 5 5

为什么不是 1 2 3 4 5,问题出在作用域上。

因为 setTimeout 的 console.log(i); 的i是 var 定义的,所以是函数级的作用域,不属于 for 循环体,属于 global。等到 for 循环结束,i 已经等于 5 了,这个时候再执行 setTimeout 的五个回调函数(参考上面对事件机制的阐述),里面的 console.log(i); 的 i 去向上找作用域,只能找到 global下 的 i,即 5。所以输出都是 5。

解决办法:人为给 console.log(i); 创造作用域,保存i的值。

解决办法一

for (var i = 0; i < 5; i++) { 
  (function(i){   //立刻执行函数
    setTimeout(function (){
      console.log(i); 
     },1000); 
  })(i); 
}

这里用到立刻执行函数。这样 console.log(i); 中的i就保存在每一次循环生成的立刻执行函数中的作用域里了。

解决办法二

for (let i = 0; i < 5; i++) {   //let 代替 var
  setTimeout(function (){
    console.log(i); 
   },1000); 
}

let 为代码块的作用域,所以每一次 for 循环,console.log(i); 都引用到 for 代码块作用域下的i,因为这样被引用,所以 for 循环结束后,这些作用域在 setTimeout 未执行前都不会被释放。

四、补充

在写示例代码的过程中,发现一个语法点:

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

报错:

TypeError: "callback" argument must be a function
at setTimeout (timers.js:421:11)
……

百度了下,原来 setTimeout 不支持传带参数的函数,可以再用一个匿名函数包装下它吧,见下面代码:

function a(i){ 
  console.log(i);  
}
for (var i = 0; i < 5; i++) { 
  setTimeout(function(){ //用匿名函数包装
    a(i);
  },1000); 
}

总结

以上所述是小编给大家介绍的for循环 + setTimeout 结合一些示例(前端面试题),希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
js模拟弹出效果代码修正版
Aug 07 Javascript
jQuery 设置 CSS 属性示例介绍
Jan 16 Javascript
JSON.parse()和JSON.stringify()使用介绍
Jun 20 Javascript
AngularJS基础知识
Dec 21 Javascript
js控制输入框获得和失去焦点时状态显示的方法
Jan 30 Javascript
javascript实现二级级联菜单的简单制作
Nov 19 Javascript
Bootstrap笔记—折叠实例代码
Mar 13 Javascript
js实现一键复制功能
Mar 16 Javascript
用vue2.0实现点击选中active其他选项互斥的效果
Apr 12 Javascript
vue做移动端适配最佳解决方案(亲测有效)
Sep 04 Javascript
微信小程序人脸识别功能代码实例
May 07 Javascript
vue使用vuex实现首页导航切换不同路由的方法
May 08 Javascript
详解使用nvm管理多版本node的方法
Aug 30 #Javascript
jquery插件开发之选项卡制作详解
Aug 30 #jQuery
浅谈angular.js跨域post解决方案
Aug 30 #Javascript
详解a++和++a的区别
Aug 30 #Javascript
详解vue2.0 使用动态组件实现 Tab 标签页切换效果(vue-cli)
Aug 30 #Javascript
angular4 如何在全局设置路由跳转动画的方法
Aug 30 #Javascript
浅谈Vue.js应用的四种AJAX请求数据模式
Aug 30 #Javascript
You might like
Yii2针对指定url的生成及图片等的引入方法小结
2016/07/18 PHP
分别用marquee和div+js实现首尾相连循环滚动效果,仅3行代码
2011/09/21 Javascript
基于jQuery的动态增删改查表格信息,可左键/右键提示(原创自Zjmainstay)
2012/07/31 Javascript
js计算两个时间之间天数差的实例代码
2013/11/19 Javascript
jquery实现类似EasyUI的页面布局可改变左右的宽度
2020/09/12 Javascript
jQuery的each循环用法简单示例
2016/06/12 Javascript
AngularJS实现按钮提示与点击变色效果
2016/09/07 Javascript
localStorage的黑科技-js和css缓存机制
2017/02/06 Javascript
vue组件中点击按钮后修改输入框的状态实例代码
2017/04/14 Javascript
浅析JS抽象工厂模式
2017/12/14 Javascript
如何在vue中使用ts的示例代码
2018/02/28 Javascript
Layui组件Table绑定行点击事件和获取行数据的方法
2018/08/19 Javascript
vue遍历生成的输入框 绑定及修改值示例
2019/10/30 Javascript
Vue实现图片与文字混输效果
2019/12/04 Javascript
Node.js API详解之 zlib模块用法分析
2020/05/19 Javascript
[36:22]VP vs Serenity 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
python通过get,post方式发送http请求和接收http响应的方法
2015/05/26 Python
Python中动态检测编码chardet的使用教程
2017/07/06 Python
Python3 把一个列表按指定数目分成多个列表的方式
2019/12/25 Python
HTML5 图片预加载的示例代码
2020/03/25 HTML / CSS
Sandro Paris美国官网:典雅别致的法国时尚服饰品牌
2017/12/26 全球购物
纽约海:Sea New York
2018/11/04 全球购物
美国牛仔品牌:True Religion
2018/11/16 全球购物
美国厨房和园艺工具网上商店:Nestneed
2019/08/24 全球购物
ASICS印度官方网站:日本专业运动品牌
2020/06/20 全球购物
广州喜创信息技术有限公司JAVA软件工程师笔试题
2012/10/17 面试题
行政办公员自我评价分享
2013/12/14 职场文书
留学顾问岗位职责
2014/04/14 职场文书
城管综合整治方案
2014/05/01 职场文书
拔河比赛口号
2014/06/10 职场文书
应届毕业生求职信范文
2014/07/07 职场文书
2015年度员工自我评价范文
2015/03/11 职场文书
2015年学校教科室工作总结
2015/07/20 职场文书
Python实现socket库网络通信套接字
2021/06/04 Python
angular异步验证器防抖实例详解
2022/03/31 Javascript
python 使用pandas读取csv文件的方法
2022/12/24 Python