网站首页 > 基础教程 正文
前言
且看下面代码:
可能一部分人答0到9,可能一部分人答10再看浏览器的回答:
那么,现在有两个疑问:
为什么会循环打印十个10而不是0到9?
从结果来看,for循环执行完跳出之后,才开始执行setTimeout(所以j才等于10),为什么不是每次迭代都执行一次setTimeout呢?
实际上应该主要涉及两块内容
先看线程
JavaScript设计的初衷,是浏览器用来与用户进行交互和DOM操作的。这就决定了它必须是单线程的,设想JavaScript同事有两个线程,一个线程在DOM节点添加内容,一个线程删除该节点,浏览器就会出现混乱。所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征。
单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。
为了优化单线程的性能,JavaScript将任务分成两种,一种是同步任务(synchronous),另一种是异步任务。
同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有主线程中的同步任务执行完毕,异步任务才会进入执行队列执行。
只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。这个过程会不断重复。而setTimeout,就被JavaScript定义为异步任务。每次for循环的迭代,都将setTimeout中的回调函数加入任务队列等待执行。
再看作用域
当然现在es6有let可以定义局部作用域,但是在这以前,是没有块状作用域的,这就意味着, 在for循环中用var定义的变量j,其实是属于全局的,即在全局范围内都可以被访问到,既然如此,那其实整个全局作用域中就只有一个j,每次for循环都i是在更新这个j。
所以整体来看,同步任务中的for循环完全结束,主线程中会去任务队列中找到尚未执行的十个setTimeout(十次迭代)回调函数并顺序执行(先进先出)。而此时,i已经经过循环结束变成了10,所以,此时主线程执行的,是十个一摸一样的打印i的回调函数,即打印十个10。
这个题也可以转化为对闭包的考题,欢迎同学留言对于开头那道题输出0到9的闭包可以有什么写法?
猜你喜欢
- 2024-11-04 可视化的 js:动态图演示 Promises & Async/Await 的过程
- 2024-11-04 JavaScript 回调 javascript 回调函数中的this
- 2024-11-04 setTimeout和setImmediate到底谁先执行
- 2024-11-04 面试官:为什么Promise比setTimeout() 快?
- 2024-11-04 淘宝小部件 Canvas 渲染流程与原理全解析
- 2024-11-04 微软 Win11/10 Edge 浏览器 Beta 105 发布(附更新内容)
- 2024-11-04 setTimeout、Promise、Async/await的区别
- 2024-11-04 通过Promise + setTimeout,实现JavaScript 的同步延迟简单示例
- 2024-11-04 Vue短文:如何在Vue.js中使用setTimeout?
- 2024-11-04 一文搞懂setTimeout和setInterval区别
- 最近发表
- 标签列表
-
- jsp (69)
- gitpush (78)
- gitreset (66)
- python字典 (67)
- dockercp (63)
- gitclone命令 (63)
- dockersave (62)
- linux命令大全 (65)
- pythonif (86)
- location.href (69)
- dockerexec (65)
- tail-f (79)
- queryselectorall (63)
- location.search (79)
- bootstrap教程 (74)
- 单例 (62)
- linuxgzip (68)
- 字符串连接 (73)
- html标签 (69)
- c++初始化列表 (64)
- mysqlinnodbmyisam区别 (63)
- arraylistadd (66)
- mysqldatesub函数 (63)
- window10java环境变量设置 (66)
- c++虚函数和纯虚函数的区别 (66)