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 相关文章推荐
实现网页页面跳转的几种方法(meta标签、js实现、php实现)
May 20 Javascript
js调试工具Console命令详解
Oct 21 Javascript
纯javascript代码实现计算器功能(三种方法)
Sep 07 Javascript
JavaScript ParseFloat()方法
Dec 18 Javascript
功能强大的Bootstrap组件(结合js)
Aug 03 Javascript
聊一聊jQuery插件uploadify使用方法
Aug 24 Javascript
AngularJS入门教程之数据绑定用法示例
Nov 01 Javascript
VUE元素的隐藏和显示(v-show指令)
Jun 23 Javascript
webpack4.0+vue2.0利用批处理生成前端单页或多页应用的方法
Jun 28 Javascript
小程序如何定位所在城市及发起周边搜索
Feb 11 Javascript
vue项目中使用rem,在入口文件添加内容操作
Nov 11 Javascript
微信小程序实现购物车小功能
Dec 30 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单件模式结合命令链模式使用说明
2008/09/07 PHP
php解决约瑟夫环示例
2014/04/09 PHP
php中使用session防止用户非法登录后台的方法
2015/01/27 PHP
PHP-FPM实现性能优化
2016/03/31 PHP
浅析Yii2 gridview实现批量删除教程
2016/04/22 PHP
微信公众平台开发(五) 天气预报功能开发
2016/12/03 PHP
PHP实现APP微信支付的实例讲解
2018/02/10 PHP
使用laravel的Eloquent模型如何获取数据库的指定列
2019/10/17 PHP
javascript得到XML某节点的子节点个数的脚本
2008/10/11 Javascript
javascript函数重载解决方案分享
2014/02/19 Javascript
jQuery事件处理的特征(事件命名机制)
2016/08/23 Javascript
详解vue-cli快速构建项目以及引入bootstrap、jq
2017/05/26 Javascript
vue、react等单页面项目应该这样子部署到服务器
2018/01/03 Javascript
vue实现组件之间传值功能示例
2018/07/13 Javascript
js实现无缝滚动双图切换效果
2019/07/09 Javascript
使用layui的layer组件做弹出层的例子
2019/09/27 Javascript
webpack是如何实现模块化加载的方法
2019/11/06 Javascript
使用JS来动态操作css的几种方法
2019/12/18 Javascript
详解ES6新增字符串扩张方法includes()、startsWith()、endsWith()
2020/05/12 Javascript
跟老齐学Python之玩转字符串(2)更新篇
2014/09/28 Python
Python基类函数的重载与调用实例分析
2015/01/12 Python
利用nohup来开启python文件的方法
2019/01/14 Python
python+selenium 点击单选框-radio的实现方法
2019/09/03 Python
python 实现目录复制的三种小结
2019/12/04 Python
python实现滑雪游戏
2020/02/22 Python
python3 sleep 延时秒 毫秒实例
2020/05/04 Python
python利用蒙版抠图(使用PIL.Image和cv2)输出透明背景图
2020/08/04 Python
Python爬取股票信息,并可视化数据的示例
2020/09/26 Python
突袭HTML5之Javascript API扩展1—Web Worker异步执行及相关概述
2013/01/31 HTML / CSS
医学院学生求职简历的自我评价
2013/10/24 职场文书
数学国培研修感言
2014/02/13 职场文书
《狮子和兔子》教学反思
2014/03/02 职场文书
党员批评与自我批评(5篇)
2014/09/23 职场文书
2015年高中班主任工作总结
2015/04/30 职场文书
关于国庆节的广播稿
2015/08/19 职场文书
党风廉政教育心得体会2016
2016/01/22 职场文书