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 相关文章推荐
jQuery $.each遍历对象、数组用法实例
Apr 16 Javascript
HTML5之WebSocket入门3 -通信模型socket.io
Aug 21 Javascript
javascript html5实现表单验证
Mar 01 Javascript
vue的props实现子组件随父组件一起变化
Oct 27 Javascript
Three.js入门之hello world以及如何绘制线
Sep 25 Javascript
two.js之实现动画效果示例
Nov 06 Javascript
angularJS开发注意事项
May 26 Javascript
浅析Vue 生命周期
Jun 21 Javascript
解决使用bootstrap的dropdown部件时报错:error:Bootstrap dropdown require Popper.js问题
Aug 30 Javascript
JavaScript修改注册表实例代码
Jan 05 Javascript
vue搜索页开发实例代码详解(热门搜索,历史搜索,淘宝接口演示)
Apr 11 Javascript
微信小程序图片右边加两行文字的代码
Apr 23 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
php ci框架中加载css和js文件失败的解决方法
2014/03/03 PHP
php检测数组长度函数sizeof与count用法
2014/11/17 PHP
浅谈PHP命令执行php文件需要注意的问题
2016/12/16 PHP
php表单处理操作
2017/11/16 PHP
php处理多图上传压缩代码功能
2018/06/13 PHP
jQuery 获取对象 基本选择与层级
2010/05/31 Javascript
JavaScript原型继承之基础机制分析
2011/08/26 Javascript
JavaScript插件化开发教程 (二)
2015/01/27 Javascript
js+html5实现的自由落体运动效果代码
2016/01/28 Javascript
javascript动态获取登录时间和在线时长
2016/02/25 Javascript
全面解析Bootstrap中tab(选项卡)的使用方法
2016/06/06 Javascript
浅析Bootstrap验证控件的使用
2016/06/23 Javascript
Angularjs实现mvvm式的选项卡示例代码
2016/09/08 Javascript
Jquery循环截取字符串的方法(多出的字符串处理成&quot;...&quot;)
2016/11/28 Javascript
基于Vue过渡状态实例讲解
2017/09/14 Javascript
webstorm添加*.vue文件支持
2018/05/08 Javascript
javascript中的event loop事件循环详解
2018/12/14 Javascript
微信小程序canvas截取任意形状的实现代码
2020/01/13 Javascript
微信小程序多列表渲染数据开关互不影响的实现
2020/06/05 Javascript
通过实例浅析Python对比C语言的编程思想差异
2015/08/30 Python
解决Python 遍历字典时删除元素报异常的问题
2016/09/11 Python
pandas 根据列的值选取所有行的示例
2018/11/07 Python
Python深拷贝与浅拷贝用法实例分析
2019/05/05 Python
Python实现FTP文件传输的实例
2019/07/07 Python
Python中的几种矩阵乘法(小结)
2019/07/10 Python
python傅里叶变换FFT绘制频谱图
2019/07/19 Python
简单了解Django ContentType内置组件
2019/07/23 Python
pytorch方法测试——激活函数(ReLU)详解
2020/01/15 Python
python画图常规设置方式
2020/03/05 Python
描述Cookie和Session的作用,区别和各自的应用范围,Session工作原理
2015/03/25 面试题
高中自我鉴定范文
2013/11/03 职场文书
化学专业毕业生自荐信
2013/11/15 职场文书
致1500米运动员广播稿
2014/02/07 职场文书
工作保证书怎么写
2015/02/28 职场文书
感恩的心主题班会
2015/08/12 职场文书
公司年会主持词范文!
2019/05/07 职场文书