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中绑定事件的命名空间详解
Apr 05 Javascript
图片在浏览器中底部对齐 解决方法之一
Nov 30 Javascript
当jQuery1.7遇上focus方法的问题
Jan 26 Javascript
JS组件Bootstrap实现弹出框和提示框效果代码
Dec 08 Javascript
轻松实现Bootstrap图片轮播
Apr 20 Javascript
jquery中实现时间戳与日期相互转换
Apr 12 Javascript
JS中的==运算: [''] == false —&gt;true
Jul 24 Javascript
jQuery实现jQuery-form.js实现异步上传文件
Apr 28 jQuery
解决vue中修改了数据但视图无法更新的情况
Aug 27 Javascript
js实现图片区域可点击大小随意改变(适用移动端)代码实例
Sep 11 Javascript
vue项目引入ts步骤(小结)
Oct 31 Javascript
vue3引入highlight.js进行代码高亮的方法实例
Apr 08 Vue.js
详解使用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
收音机术语解释
2021/03/01 无线电
php中全局变量global的使用演示代码
2011/05/18 PHP
微信公众平台网页授权获取用户基本信息中授权回调域名设置的变动
2014/10/21 PHP
总结PHP代码规范、流程规范、git规范
2018/06/18 PHP
redis+php实现微博(一)注册与登录功能详解
2019/09/23 PHP
JAVASCRIPT HashTable
2007/01/22 Javascript
jquery 的 $(&quot;#id&quot;).html() 无内容的解决方法
2010/06/07 Javascript
jquery中event对象属性与方法小结
2013/12/18 Javascript
使用js获取图片原始尺寸
2014/12/03 Javascript
浅谈javascript中自定义模版
2015/01/29 Javascript
Javascript 字符串模板的简单实现
2016/02/13 Javascript
vue2.0父子组件及非父子组件之间的通信方法
2017/01/21 Javascript
Angular 4依赖注入学习教程之ValueProvider的使用(七)
2017/06/04 Javascript
bootstrap table实现x-editable的行单元格编辑及解决数据Empty和支持多样式问题
2017/08/10 Javascript
解决vue热替换失效的根本原因
2018/09/19 Javascript
用npm安装vue和vue-cli,并使用webpack创建项目的方法
2018/09/28 Javascript
JQuery获取元素尺寸、位置及页面滚动事件应用示例
2019/05/14 jQuery
vue实现购物车的小练习
2020/12/21 Vue.js
python实现的阳历转阴历(农历)算法
2014/04/25 Python
tensorflow学习笔记之mnist的卷积神经网络实例
2018/04/15 Python
在PyCharm下打包*.py程序成.exe的方法
2018/11/29 Python
Python 用三行代码提取PDF表格数据
2019/10/13 Python
OpenCV python sklearn随机超参数搜索的实现
2020/01/17 Python
Python 动态变量名定义与调用方法
2020/02/09 Python
python 中的命名空间,你真的了解吗?
2020/08/19 Python
HTML5 Canvas图像模糊完美解决办法
2018/02/06 HTML / CSS
WWE美国职业摔角官方商店:WWE Shop
2018/11/15 全球购物
大学生实习期自我评价范文
2013/10/03 职场文书
签约仪式主持词
2014/03/19 职场文书
授权委托书范本
2014/04/03 职场文书
文案策划求职信
2014/04/14 职场文书
亲子阅读的活动方案
2014/08/15 职场文书
2014年民政工作总结
2014/11/26 职场文书
民间借贷被告代理词
2015/05/23 职场文书
mysql insert 存在即不插入语法说明
2022/03/25 MySQL
Python绘制散乱的点构成的图的方法
2022/04/21 Python