JavaScript单线程和异步机制
随着对JavaScript学习的深入和实践经验的积累,一些原理和底层的东西也开始逐渐了解。早先也看过一些关于js单线程和事件循环的文章,不过当时看的似懂非懂,只留了一个大概的印象:浏览器中的js程序时是单线程的。嗯,就这么点印象。当时也有些疑问:既然是单线程的,那异步调用是怎么实现的?计时器是靠谁来计时的,这单线程总不能一边执行程序一边计时吧?那些耗时的I/O操作为啥没把线程阻塞,不是说好的单线程么?相信很多不了解JavaScript单线程的同学也有过类似的疑问。
今天看了不少相关的资料,就详细地总结一下,希望能帮到大家,同时自己也梳理一下知识点,理解是一回事,能写下来是另一回事。好了,开始正文。
一、JavaScript单线程
在浏览器的一个页面中,该页面的JS程序只有一个线程,故曰单线程。因为是单线程,所以程序的执行顺序就是从上到下依次执行,同一时间内只能有一段代码被执行。那为什么不用多线程,这样不是更能充分利用CPU,提高效率么?
早期的网页内容非常简单,单线程足以应付,所以在设计之初,我估计设计者就没考虑使用多线程。另外,JavaScript主要用来处理用户与页面产生的交互,以及操作DOM;如果以多线程的方式来操作DOM,一个线程要求删除该DOM,另一个要求修改DOM样式,那么浏览器该听谁的?这大大增加了程序设计的复杂度,本来前端都不好学,不是么~~~简简单单多好。
虽然JavaScript是单线程的,可是浏览器内部不是单线程的。你的一些I/O操作、定时器的计时和事件监听(click, keydown…)等都是由浏览器提供的其他线程来完成的。
如果想利用多线程处理一些耗时较长的任务,可以使用HTML5提出的Web Worker。
二、任务队列和事件循环
提到异步机制,不得不说到任务队列和事件循环,这里理解JS异步机制的要点。
首先理解浏览器的并发模型,来看下面这个图:
左边的栈存储的是同步任务,所谓同步的任务就是那些能立即执行、不耗时的任务,如变量和函数的初始化、事件的绑定等等那些不需要回调函数的操作都可归为这一类。右边的堆用来存储声明的变量、对象。下面的队列就是任务队列,一旦某个异步任务有了响应就会被推入队列中。如用户的点击事件、浏览器收到服务的响应和后面提到的setTimeout插入的事件。每个异步任务都和一个回调函数相关联。
一个js程序的单线程用来执行栈中的同步任务,当所有同步任务执行完毕后,栈被清空,然后读取任务队列中的一个待处理任务,并把相关回调函数压入栈中,单线程开始执行新的同步任务,执行完毕。
单线程从任务队列中读取任务是不断循环的,每次栈被清空后,都会在任务队列中读取新的任务,如果没有新的任务,就会等待,直到有新的任务,这就叫任务循环。因为每个任务都由一个事件所触发,所以也叫事件循环。
三、异步机制
有了上面两节做铺垫,理解异步机制就容易多了。拿ajax来说,当页面的单线程执行xhr.send()
之后,对于页面来说发送任务已经完成了。怎么发送,那是浏览器的事,和单线程无关;什么时候响应,这事说不准。为了及时地得到响应的内容,在单线程中注册相应的事件就好xhr.onreadystatechange = fn() {...}
。注册之后,浏览器会在内部的其他线程中自动地帮我们监听该事件。直到该事件被触发,浏览器会在任务队列中添加一个任务等待该单线程执行。
四、定时器
setTimeout的作用是在间隔一定的时间后,将回调函数插入任务队列中,等栈中的同步任务都执行完毕后,再执行。因为栈中的同步任务也会耗时,所以间隔的时间一般会大于等于指定的时间。
setTimeout(fn, 0)
的意思是,将回调函数fn立刻插入任务队列,等待执行,而不是立即执行。看一个例子:
1
2
3
4
5
6
7
8
|
setTimeout(function() {
console.log("a")
}, 0)
for(let i=0; i<10000; i++) {}
console.log("b")
// 结果:b a
|
打印结果表明回调函数并没有立刻执行,而是等待栈中的任务执行完毕后才执行的。栈中的任务执行多久,它就得等多久。
五、总结
JavaScript单线程和其异步机制就如上所述。所谓的单线程并不孤单,它的背后有浏览器的其他线程为其服务,其异步也得靠其他线程来监听事件的响应,并将回调函数推入到任务队列等待执行。单线程所做的就是执行栈中的同步任务,执行完毕后,再从任务队列中取出一个事件(没有事件的话,就等待事件),然后开始执行栈中相关的同步任务,不断的这样循环。
参考资料
来源:http://ylcui.top/2016/08/14/JavaScript%E5%8D%95%E7%BA%BF%E7%A8%8B%E4%B8%8E%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF/?utm_source=tuicool&utm_medium=referral
JavaScript单线程和异步机制的更多相关文章
- 【本周主题】第一期:JavaScript单线程与异步
相信下边这个图一定都不陌生,本周就围绕这张图深入了解下js代码执行时的来龙去脉. 一.JavaScript是单线程的 2018-11-19 21:21:21 周一 js本质是单线程的.这一特性是jav ...
- javascript单线程,异步与执行机制
js的单线程模型与游览器的进程/线程息息相关,在了解js单线程与异步的时候,建议先看看这篇文章 为什么是单线程 由于js是可操作dom的,如果js是多线程,在多线程的交互下,处于界面中的dom节点就可 ...
- [转]JavaScript异步机制详解
原文: https://www.jianshu.com/p/4ea4ee713ead --------------------------------------------------------- ...
- 【本周面试题】第2周 - js单线程和异步相关问题
硬性知识点考察: 为什么js是单线程的? 因为js设计最初是为了操作dom而生,如果是多线程的,当多个线程同时修改一个dom时就会产生冲突,所以设计成单线程,一次只能做一件事. 既然是单线程为什么要有 ...
- JavaScript异步机制
单线程异步执行的JavaScript JavaScript是单线程异步执行的,单线程意味着代码在任务队列中会按照顺序一个接一个的执行.异步代表JavaScript代码在任务队列中的顺序并不完全等同于代 ...
- 我理解的javascript单线程机制
废话不多说,我们先来看几个例子: 1. setTimeout( console.log(2); result: 2 1 2. console.log(100 setTimeout( cons ...
- JavaScript的异步机制
我们经常说JS是单线程的,比如node.js研讨会上大家都说JS的特色之一是单线程的,这样使JS更简单明了,可是大家真的理解所谓JS的单线程机制吗?单线程时,基于事件的异步机制又该当如何 1 先看下两 ...
- 浏览器UI多线程及JavaScript单线程运行机制的理解
在上一篇博客中,我对jQuery的队列(queue)机制和动画(animate)机制做了一个深入的解析,在animate的实现机制其核心是依靠queue来完成的,其中在jQuery的链式调用部分,之前 ...
- 前端知识点回顾之重点篇——JavaScript异步机制
JavaScript异步机制 来源:https://www.cnblogs.com/zhaodongyu/p/3922961.html JavaScript是单线程异步执行的,单线程意味着代码在任务队 ...
随机推荐
- AngularJS进阶(六)AngularJS+BootStrap实现弹出对话框
AngularJS+BootStrap实现弹出对话框 参考资料: http://angular-ui.github.io/bootstrap/#/modal https://www.zybuluo.c ...
- 【LaTeX排版】LaTeX论文排版<二>
1.目录的生成 直接使用命令\tableofcontents即可.其默认格式如下: 我们会发现,这样的格式不一定是我们所期望的.比如说,我们也希望章标题与页码之间也有点连线,并且也希望将致谢. ...
- HBase行锁
1 行锁简介 在事务特性方面,hbase只支持单row的事务,不能保证跨row(cross-row)的事务.hbase通过行锁来实现单row事务.客户端进行操作时,可以显式对某一个行加锁,但是大部分情 ...
- Windows核心编程读书笔记1
今天特别困啊,这是为什么?!!刚刚把第一章看了一下,困到不行,所以写blog清醒一下. 第一章标题是“错误处理”,看了之后吓了一跳,难道第一章就讲这么高大上的东西?!不是不是,我现在的理解是,这章主要 ...
- 存储引擎-Bitcast
Bitcast是一种日志型的基于hash表结构的健值对的存储系统,最早追溯于Riak分布式数据库. 目前,Berkeley DB,Tokyo Cabinet,Innostore都使用了这种存储引擎.使 ...
- Mac OS X下各种文件编码的转换方法
何曾几时本猫还在windows下编码的时候,那时ruby的源代码的编码格式都是gbk啊!导致N多中文显示为乱码.后来无奈写了个转换代码从gbk编码转为utf-8格式的小工具: #!/usr/bin/r ...
- jquery 滚动事件
$(window).scroll(function () { if ($(window).scrollTop() >50) { alert('show!!'); }});
- 春天的事务之9.3编程式事务 - 跟我学spring3
9.3编程式事务 9.3.1编程式事务概述 所谓编程式事务指的是通过编码方式实现事务,即类似于JDBC编程实现事务管理. Spring框架提供一致的事务抽象,因此对于JDBC还是JTA事务都是采用相同 ...
- python---购物车
购物车功能如下: 1. 输入收入多少,购买商品 2. 打印购物清单,根据清单选择商品: 3. 结算,打印购物清单及总金额 # -*- coding:utf-8 -*- # LC goods=[[1,' ...
- Ubuntu12.04下Django1.4的删除目录
网上有很多文章说这个问题,大意就是下载压缩包以后用 sudo python setup.py install 上面这条命令安装的Django,然后到相关目录下把那个Django的目录删掉就Ok了,但是 ...