js setTimeout的三种情况
在for循环中运行setTimeout是前端开发很常见的一种模式。最近被考了一道相关的题目觉得很有意思也很容易犯错,于是记录下来当做学习笔记。
下面先来看一段代码:
for(var i=0;i<10;i++){setTimeout(console.log(i),0);}
看完这段代码思考一下结果输出是什么呢?
是不是第一时间想到的是连续的10个10呢?啊哈哈这样就错啦~
答案是0、1、2、3、4、5、6、7、8、9哦,这是因为很多人把这段代码与下面的代码混淆了
for(var i=0;i<10;i++){setTimeout(function(){console.log(i); //连续的10个10},0);}
这段代码输出结果是连续的10个10。
首先我们来说一下为什么是连续的10个10。因为在for循环中使用setTimeout涉及到了异步机制。说到异步机制那就要说一下JS的运行机制。
JS是单线程环境,也就是说代码的执行是从上到下,依次执行。也就是同一个时间只能做一件事。
单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。JavaScript将所有任务分成两种,一种是同步任务,另一种是异步任务。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
在所有同步任务执行完之前,任何的异步任务是不会执行的。 而setTimeout就是一个异步任务,所以会先执行for循环这个同步任务,把setTimeout()放进任务队列中等待主线程的for循环执行完毕,一旦"执行栈"中的所有同步任务执行完毕(循环结束后此时i=10)就会从队列中取出setTimeout()
for循环一次碰到一个 setTimeout(),并不是马上把setTimeout()拿到异步队列中,而要等到一秒后,才将其放到任务队列里面。
异步执行的运行机制如下:
所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
主线程不断重复上面的第三步。
主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。这个过程会循环反复。
一般来说,有以下四种会放入异步任务队列:
- setTimeout和setlnterval
- DOM事件
- ES6中的Promise
- Ajax异步请求
回归正题,既然在for循环中运行setTimeout()涉及到了异步,那上面的解释不就解决问题了吗,可是为什么第一段代码结果不是连续的10个10呢?这就涉及到了console.log 与console.log()的区别了。
看下面代码:
看懂了吗,看懂了这道题也就解决了啊哈哈
其实console.log 与console.log()的区别就是 console.log()是立即执行的也就是IIFE,而console.log只是一个function 函数名。所以console.log()是同步任务跟for循环是同步执行的,而setTimeout()是异步任务需要等到主线程的同步任务执行完毕后才能执行,所以结果就是0、1、2、3、4、5、6、7、8、9了。
再来看一段代码:
for(var i=0;i<10;i++){setTimeout("console.log(i)",1000);//连续的10个10}
啊哈哈,这时候结果就是连续的10个10了。
原因在于加了双引号的console.log()不再是立即执行函数。setTimeout() 会判断第一个参数是否是[function],如果不是,则会尝试将它当做字符串处理。也就是说,console.log(i)执行后的返回值转为字符串。
现在明白在for循环中运行setTimeout()的三种情况区别了吧
for(var i=0;i<10;i++){setTimeout(console.log(i),0);//0、1、2、3、4、5、6、7、8、9}for(var i=0;i<10;i++){setTimeout(function(){console.log(i);//连续的10个10},0);}for(var i=0;i<10;i++){setTimeout("console.log(i)",1000);//连续的10个10}
参考文章
https://blog.csdn.net/Febby_/article/details/89513819
异步知识参考来源:
https://baijiahao.baidu.com/s?id=1615713540466951098&wfr=spider&for=pc
js setTimeout的三种情况相关推荐
- 在for循环中运行setTimeout的三种情况
在for循环中运行setTimeout是前端开发很常见的一种模式.最近被考了一道相关的题目觉得很有意思也很容易犯错,于是记录下来当做学习笔记. 下面先来看一段代码: for(var i=0;i< ...
- ES6中let的用法及一个小案例,在for循环中运行setTimeout的四种情况:
1.ES6中let和var的主要区别: (1)let声明的变量只在当前块级作用域内有效. if(true){var a=1;let b=2; } console.log(a); console.log ...
- 【重复提交表单】表单重复提交的三种情况,解决办法
引入 看一个重复提交表单的例子 F12可以看到,请求体中的参数在刷新页面之后仍然保留,因此每一次刷新页面,都会把现有的请求体中的表单数据提交一次到服务器,而接收的页面还是insert.jsp,于是造成 ...
- java基础:map遍历使用;java使用 Patten 和Matches 进行正则匹配;后端传到前端展示图片三种情况,并保存到手机;
文章目录 前言 一.map 遍历方法 二.java正则学习 三.后端传到前端图片三种情况 1. 图片流数据(InputStream) 转 base64,前端展示保存 a. 后端:输入流转base,直接 ...
- 对象的notify方法的含义和对象锁释放的三种情况
1,notify的含义 (1)notify一次只随机通知一个线程进行唤醒 (2)在执行了notify方法之后,当前线程不会马上释放该对象锁,呈wait状态的线程也不能马上获得该对象锁, 要等到 ...
- SSO单点登录三种情况的实现方式详解
SSO单点登录三种情况的实现方式详解 单点登录(SSO--Single Sign On)对于我们来说已经不陌生了.对于大型系统来说使用单点登录可以减少用户很多的麻烦.就拿百度来说吧,百度下面有很多的子 ...
- 野指针出现的三种情况
昨天面试被问到"你了解野指针吗",我的回答是"野指针就是没有初始化的指针,这样的指针会随机指向一块内存,野指针会对系统造成破坏(造成内存泄漏)".面试官又问到, ...
- mysql002多表查询.on链接分为三种情况,左链接,右链接,全链接
-- on链接(最实用),分为三种情况,左链接,右链接,全链接 -- 左外链接,左表全部显示,如果匹配不到右表的内容使用null代替. SELECT * FROM emp e LEFT JOIN de ...
- shiro单点登录原理_SSO单点登录三种情况的实现方式详解
单点登录(SSO--Single Sign On)对于我们来说已经不陌生了.对于大型系统来说使用单点登录可以减少用户很多的麻烦.就拿百度来说吧,百度下面有很多的子系统--百度经验.百度知道.百度文库等 ...
最新文章
- 二叉树的四种遍历方式(递归和非递归双重实现)
- Java多线程之单例模式在多线程环境下的安全问题
- Mybatis之加载mybatis-config.xml
- 微信可以远程控制电脑吗_用微信就能远程控制电脑,这款神器有些厉害
- ORACLE JOB 失败 查看,Oracle JOB异常中断原因分析
- Python求解进制问题(阿里巴巴2015笔试题)
- 关于含光 800,这里有你想要的一切答案!
- shell脚本不换行刷新数据
- mysql 配置root密码_Mysql安装与配置调优及修改root密码的方法
- 21. Django进阶:内建用户系统
- 20个开发人员非常有用的Java功能代码(一)
- json标准格式举例_JSON 数据格式详解
- spark的数三角形算法_腾讯开源全栈机器学习平台 Angel 3.0,支持三大类型图计算算法...
- 学术界AV1编码优化技术的进展
- Python常用配置文件ini、json、yaml读写总结
- 1099:零起点学算法06——再来一题除法算术题
- 【学习笔记】常见测试类型测试方法
- 软件工程应用与实践(1)——项目简介和小组分工
- 基于微信小程序的校园二手交易
- 搭建个人的Leanote云笔记本