有趣的setTimeout
今天在回顾JavaScript进阶用法的时候,发现一个有趣的问题,话不多说,先上代码:
for(var j=0;j<10;j++){
setTimeout(function(){console.log(j)},5000)
}
看到这三行代码,也许你会不耐烦道:又要讲闭包?要吐了好么?别急,让我们先来思考一下,这段代码在浏览器中的执行结果是什么?
执行结果显示,浏览器打印出了十个10
家都知道,JavaScript在ES6出现以前,是没有块状作用域的,这就意味着, 在for循环中用var定义的变量j,其实是属于全局的,即在全局范围内都可以被访问到,既然如此,那其实整个全局作用域中就只有一个j,每次for循环都i是在更新这个j。
那么现在关键的问题在于,为什么整个for循环会先于setTimeout执行,而不是我们正常理解的,一次迭代执行一次。
这就涉及到了JavaScript的核心特性:单线程。
JavaScript设计的初衷,是浏览器用来与用户进行交互和DOM操作的。这就决定了它必须是单线程的,设想JavaScript同事有两个线程,一个线程在DOM节点添加内容,一个线程删除该节点,浏览器就会出现混乱。所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。
单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。
为了优化单线程的性能,JavaScript将任务分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有主线程中的同步任务执行完毕,异步任务才会进入执行队列执行。只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。这个过程会不断重复。
而setTimeout,就被JavaScript定义为异步任务。每次for循环的迭代,都将setTimeout中的回调函数加入任务队列等待执行。也就是说,只有同步任务中的for循环完全结束,主线程中才会去任务队列中找到尚未执行的十个setTimeout(十次迭代)回调函数并顺序执行(先进先出)。而此时,i已经经过循环结束变成了10,所以,此时主线程执行的,是十个一摸一样的打印i的回调函数,即打印十个10。至此就完美回答了第一和第二个问题,文章开头的代码与下面的代码其实是等价的:
for(var i=0;i<10;i++){}
setTimeout(console.log(i),5000)
setTimeout(console.log(i),5000)
setTimeout(console.log(i),5000)
setTimeout(console.log(i),5000)
setTimeout(console.log(i),5000)
setTimeout(console.log(i),5000)
setTimeout(console.log(i),5000)
setTimeout(console.log(i),5000)
setTimeout(console.log(i),5000)
setTimeout(console.log(i),5000)
有趣的setTimeout的更多相关文章
- 你不知道的Javascript:有趣的setTimeout
你不知道的Javascript:有趣的setTimeout 有时候,小小的细节往往隐藏着大大的智慧今天在回顾JavaScript进阶用法的时候,发现一个有趣的问题,话不多说,先上代码: for(var ...
- 每个JavaScript工程师都应懂的33个概念
摘要: 基础很重要啊! 原文:33 concepts every JavaScript developer should know 译文:每个 JavaScript 工程师都应懂的33个概念 作者:s ...
- 每个 JavaScript 工程师都应懂的33个概念
简介 这个项目是为了帮助开发者掌握 JavaScript 概念而创立的.它不是必备,但在未来学习(JavaScript)中,可以作为一篇指南. 本篇文章是参照 @leonardomso 创立,英文版项 ...
- 【小贴士】关于transitionEnd/animate的一个有趣故事
前言 在很久之前,我们项目有一个动画功能,功能本身很简单,便是典型的右进左出,并且带动画功能 以当时来说,虽然很简单,但是受限于框架本身的难度,就直接使用了CSS3的方式完成了功能 当时主要使用tra ...
- js中setTimeout()时间参数设置为0的探讨
起因源于一道前端笔试题: var fuc = [1,2,3]; for(var i in fuc){ setTimeout(function(){console.log(fuc[i])},0); co ...
- setTimeout 第三个参数 改变setTimeout的作用对象 控制下拉框的关闭
setTimeout第三个参数,可以作为setTimeout延时执行函数的传入参数使用,利用这个设定,我们可以将要延时改变状态的对象传入,变相改变setTimeout的作用对象:这里setTimeou ...
- 浅谈setTimeout函数和setInterval函数
前几天学了js,看到了两个非常有趣的函数,他们分别是setTimeout函数和setInterval函数,这两个函数能使网页呈现非常一些网页中比较常见的效果,比如说图片轮播,等一些非常好玩的效果.下面 ...
- 有趣的win8进度条
有趣的win8进度条 刚才在安装visual studio 12,发现它的安装界面都是win8风格的,而且安装的时候有个进度条,看着挺不错,就用 jquery 实现了一下,的确挺有趣: 点击停止效果 ...
- setTimeout与setInterval参数之String
今天无意中给某网友解答了一些setTimeout的问题,发现一个有趣的东西. 以前我总认为setTimeout的第一个参数只能function,后面发现string也能执行.那问题来了,String做 ...
随机推荐
- HDU2065"红色病毒"问题【指数型母函数】
Problem Description 医学界发现的新病毒因其蔓延速度和Internet上传播的"红色病毒"不相上下,被称为"红色病毒",经研究发现,该病毒及其 ...
- 小组项目需求——NABCD
关于项目微食堂的NABCD: N(need): 就我自己而言,每天在上午三四节课时就会想中午吃什么.而且大部分的课在二教,离食堂较远.可能会面临“抢不到饭”的问题.首先不知道去哪吃.吃什么,尤其在时间 ...
- Audiophobia(Floyd算法)
个人心得:这在一定途径上完成查询方面还是很吃力,得多锻炼空间能力,不能再每次都看到就后退,要全力应对, 那怕被虐的不要不要的. 这题主要是求俩个端点中所有路径中最大构成的集合中最小的数值,其实开始思想 ...
- 转: 全局变量报错:UnboundLocalError: local variable 'l' referenced before assignment
http://blog.csdn.net/my2010sam/article/details/17735159
- 清理svn.bat
@echo on color 2f mode con: cols=80 lines=25 @REM @echo 正在清理SVN文件,请稍候...... @rem 循环删除当前目录及子目录下 ...
- Python函数-abs()
说明: 返回绝对值 参数可以是:负数.正数.浮点数或者长整形 实例: abs(-1.2) #返回 1.2 abs(1.2) #返回 1.2 abs(-11216.5) #返回 11216.5 abs( ...
- 最长递增子序列 LIS 时间复杂度O(nlogn)的Java实现
关于最长递增子序列时间复杂度O(n^2)的实现方法在博客http://blog.csdn.net/iniegang/article/details/47379873(最长递增子序列 Java实现)中已 ...
- redis4.0.1集群安装部署
安装环境 序号 项目 值 1 OS版本 Red Hat Enterprise Linux Server release 7.1 (Maipo) 2 内核版本 3.10.0-229.el7.x86_64 ...
- Windows SID理解
Windows安全性要依赖于几个基本元素.:访问令牌.SID.安全描述符.访问控制列表.密码. 访问令牌:访问令牌在本质上定义了两 上“P”:Permissions(权限)和Privilege(特权) ...
- AllowsTransparency和WebBrowser兼容性问题解决方案
AllowsTransparency和System.Windows.Controls.WebBrowser兼容性问题,能看这篇文章,所以原因也不用多说:最根本的就是因为MS对win32底层的WebBr ...