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 相关文章推荐
javascript下function声明一些小结
Dec 28 Javascript
基于jQuery的日期选择控件
Oct 27 Javascript
jQuery 验证插件 Web前端设计模式(asp.net)
Oct 17 Javascript
js中document.getElementByid、document.all和document.layers区分介绍
Dec 08 Javascript
在新窗口打开超链接的方法小结
Apr 14 Javascript
浅析jquery的作用与优势
Dec 02 Javascript
JavaScript Window浏览器对象模型方法与属性汇总
Apr 20 Javascript
Javascript 字符串模板的简单实现
Feb 13 Javascript
jQuery代码性能优化的10种方法
Jun 21 Javascript
让html元素随浏览器的大小自适应垂直居中的实现方法
Oct 12 Javascript
微信小程序使用npm包的方法步骤
Aug 13 Javascript
extjs图表绘制之条形图实现方法分析
Mar 06 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编程中字符串处理的5个技巧小结
2007/11/13 PHP
php之对抗Web扫描器的脚本技巧
2008/10/01 PHP
thinkphp3.0 模板中函数的使用
2012/11/13 PHP
PHP 实现页面静态化的几种方法
2017/07/23 PHP
php 根据URL下载远程图片、压缩包、pdf等文件到本地
2019/07/26 PHP
cookie丢失问题(认证失效) Authentication (用户验证信息)也会丢失
2009/06/04 Javascript
基于jquery的监控数据是否发生改变
2011/04/11 Javascript
人人网javascript面试题 可以提前实现下
2012/01/05 Javascript
javascript实现tabs选项卡切换效果(扩展版)
2013/03/19 Javascript
php显示当前文件所在的文件以及文件夹所有文件以树形展开
2013/12/13 Javascript
查找Oracle高消耗语句的方法
2014/03/22 Javascript
jQuery前端框架easyui使用Dialog时bug处理
2014/12/05 Javascript
Javascript 实现图片无缝滚动
2014/12/19 Javascript
javascript动态修改Li节点值的方法
2015/01/20 Javascript
js操作滚动条事件实例
2015/01/29 Javascript
react-router实现跳转传值的方法示例
2017/05/27 Javascript
傻瓜式解读koa中间件处理模块koa-compose的使用
2018/10/30 Javascript
antd配置config-overrides.js文件的操作
2020/10/31 Javascript
详解Vue中的watch和computed
2020/11/09 Javascript
python进程管理工具supervisor使用实例
2014/09/17 Python
fastcgi文件读取漏洞之python扫描脚本
2017/04/23 Python
Python构建图像分类识别器的方法
2019/01/12 Python
python代理工具mitmproxy使用指南
2019/07/04 Python
python+tifffile之tiff文件读写方式
2020/01/13 Python
pytorch实现mnist数据集的图像可视化及保存
2020/01/14 Python
html5 worker 实例(一) 为什么测试不到效果
2013/06/24 HTML / CSS
详解canvas多边形(蜘蛛图)的画法示例
2018/01/29 HTML / CSS
美国最便宜的旅游网站:CheapTickets
2017/07/09 全球购物
倩碧香港官方网站:Clinique香港
2017/11/13 全球购物
求高于平均分的学生学号及成绩
2016/09/01 面试题
JAVA软件工程师测试题
2014/07/25 面试题
本科毕业生求职自荐信
2014/02/03 职场文书
餐饮收银员岗位职责
2014/02/07 职场文书
询价采购方案
2014/06/09 职场文书
2015年小学教导处工作总结
2015/05/26 职场文书
go mod 安装依赖 unkown revision问题的解决方案
2021/05/06 Golang