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实现的动态添加表单元素input,button等(appendChild)
Nov 24 Javascript
JS命名空间的另一种实现
Aug 09 Javascript
js使用栈来实现10进制转8进制与取除数及余数
Jun 11 Javascript
javascript数组去重的方法汇总
Apr 14 Javascript
JS 实现可停顿的垂直滚动实例代码
Nov 23 Javascript
用vue和node写的简易购物车实现
Apr 25 Javascript
浅谈Vue-cli单文件组件引入less,sass,css样式的不同方法
Mar 13 Javascript
webpack 开发和生产并行设置的方法
Nov 08 Javascript
微信小程序如何刷新当前界面的实现方法
Jun 07 Javascript
js 判断当前时间是否处于某个一个时间段内
Sep 19 Javascript
浅析Vue 防抖与节流的使用
Nov 14 Javascript
小程序中手机号识别的示例
Dec 14 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包含文件函数include、include_once、require、require_once区别总结
2014/04/05 PHP
php递归删除目录下的文件但保留的实例分享
2014/05/10 PHP
php中ftp_chdir与ftp_cdup函数用法
2014/11/18 PHP
thinkphp框架实现数据添加和显示功能
2016/06/29 PHP
js加解密 脚本解密
2008/02/22 Javascript
JavaScript 应用技巧集合[推荐]
2009/08/30 Javascript
在js中单选框和复选框获取值的方式
2009/11/06 Javascript
Javascript面向对象之四 继承
2011/02/08 Javascript
JS 精确统计网站访问量的实例代码
2013/07/05 Javascript
JavaScript:new 一个函数和直接调用函数的区别分析
2013/07/10 Javascript
表单序列化与jq中的serialize使用示例
2014/02/21 Javascript
仿JQuery输写高效JSLite代码的一些技巧
2015/01/13 Javascript
盘点javascript 正则表达式中 中括号的【坑】
2016/03/16 Javascript
jQuery fadeOut 异步实例代码详解
2016/08/18 Javascript
用JavaScript实现让浏览器停止载入页面的方法
2017/01/19 Javascript
JQuery animate动画应用示例
2019/05/14 jQuery
Javascript 类型转换、封闭函数及常见内置对象操作示例
2019/11/15 Javascript
24行JavaScript代码实现Redux的方法实例
2019/11/17 Javascript
Python实现将16进制字符串转化为ascii字符的方法分析
2017/07/21 Python
Python使用logging模块实现打印log到指定文件的方法
2018/09/05 Python
Python何时应该使用Lambda函数
2019/07/02 Python
python3 map函数和filter函数详解
2019/08/26 Python
python 比较2张图片的相似度的方法示例
2019/12/18 Python
mac 上配置Pycharm连接远程服务器并实现使用远程服务器Python解释器的方法
2020/03/19 Python
python 如何将office文件转换为PDF
2020/09/22 Python
python 基于selectors库实现文件上传与下载
2020/12/31 Python
运动服饰每月订阅盒:Ellie
2018/04/29 全球购物
体育纪念品、亲笔签名的体育收藏品:Steiner Sports
2020/07/31 全球购物
Smilodox官方运动服装店:从运动服到健身配件
2020/08/27 全球购物
绩效考核实施方案
2014/03/18 职场文书
乡镇挂职心得体会
2014/09/04 职场文书
机关单位工作失职检讨书
2014/11/20 职场文书
先进事迹材料怎么写
2014/12/30 职场文书
初中家长意见
2015/06/03 职场文书
志愿者服务宣传标语口号
2015/12/26 职场文书
Win11任务栏太宽了怎么办?一招解决Win11任务栏太宽问题
2021/11/21 数码科技