随着对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单线程和异步机制的更多相关文章

  1. 【本周主题】第一期:JavaScript单线程与异步

    相信下边这个图一定都不陌生,本周就围绕这张图深入了解下js代码执行时的来龙去脉. 一.JavaScript是单线程的 2018-11-19 21:21:21 周一 js本质是单线程的.这一特性是jav ...

  2. javascript单线程,异步与执行机制

    js的单线程模型与游览器的进程/线程息息相关,在了解js单线程与异步的时候,建议先看看这篇文章 为什么是单线程 由于js是可操作dom的,如果js是多线程,在多线程的交互下,处于界面中的dom节点就可 ...

  3. [转]JavaScript异步机制详解

    原文: https://www.jianshu.com/p/4ea4ee713ead --------------------------------------------------------- ...

  4. 【本周面试题】第2周 - js单线程和异步相关问题

    硬性知识点考察: 为什么js是单线程的? 因为js设计最初是为了操作dom而生,如果是多线程的,当多个线程同时修改一个dom时就会产生冲突,所以设计成单线程,一次只能做一件事. 既然是单线程为什么要有 ...

  5. JavaScript异步机制

    单线程异步执行的JavaScript JavaScript是单线程异步执行的,单线程意味着代码在任务队列中会按照顺序一个接一个的执行.异步代表JavaScript代码在任务队列中的顺序并不完全等同于代 ...

  6. 我理解的javascript单线程机制

    废话不多说,我们先来看几个例子: 1. setTimeout( console.log(2); result:  2 1   2.   console.log(100 setTimeout( cons ...

  7. JavaScript的异步机制

    我们经常说JS是单线程的,比如node.js研讨会上大家都说JS的特色之一是单线程的,这样使JS更简单明了,可是大家真的理解所谓JS的单线程机制吗?单线程时,基于事件的异步机制又该当如何 1 先看下两 ...

  8. 浏览器UI多线程及JavaScript单线程运行机制的理解

    在上一篇博客中,我对jQuery的队列(queue)机制和动画(animate)机制做了一个深入的解析,在animate的实现机制其核心是依靠queue来完成的,其中在jQuery的链式调用部分,之前 ...

  9. 前端知识点回顾之重点篇——JavaScript异步机制

    JavaScript异步机制 来源:https://www.cnblogs.com/zhaodongyu/p/3922961.html JavaScript是单线程异步执行的,单线程意味着代码在任务队 ...

随机推荐

  1. EBS R12安装升级(FRESH)(三)

    5 EBS R12.1.1安装后配置 5.1 新建patch文件夹 1 2 3 su - root mkdir /stage/patch chmod 777 /stage/patch 打补丁说明:随便 ...

  2. Python和shell中Base64编码使用那些事

    做开发第一个接触的编码方式就是Base64,当时是用url来传输一些参数,传输的两端会用Base64来编码和解码,保证数据不被url转义破坏. 下面是 维基百科 Base64 中的介绍,其实自己实现起 ...

  3. redis注册成window服务

    注册服务 redis-server.exe –service-install redis.windows.conf 删除服务 redis-server –service-uninstall 开启服务 ...

  4. Java 去掉字符串中的换行符回车符等

    去掉一个字符串中的换行符.回车符等,将连续多个空格替换成一个空格 String string = "this just a test" Pattern p = Pattern.co ...

  5. rails使用QQ邮箱发送邮件蛋疼的经历

    以前本猫在blog中写过使用ruby发送邮件的博文,其中使用了163和qq的邮箱发送邮件都可以发送成功.但是现在使用rails的发送邮件功能,使用的是qq的邮件服务器发送,死活不可以!要不就是认证失败 ...

  6. java中Scanner类nextLine()和next()的区别和使用方法

    转载:http://blog.csdn.net/zhiyuan_ma/article/details/51592730 在实现字符窗口的输入时,很多人更喜欢选择使用扫描器Scanner,它操作起来比较 ...

  7. 02_Linux学习_命令

    帮助命令:        xxx --help        man xxx 列出当前目录下的目录和文件:        ls        ls -l        ls --help        ...

  8. windows安装weblogic和域的建立

    Copyright ©2014 Manchester United

  9. java四大特性理解(封装继承多态抽象)

    封装: 封装是把过程和数据包围起来,对数据的访问只能通过已定义的接口.面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治.封装的对象,这些对象通过一个受保护的接口访问其他对象.封装是一 ...

  10. 关于eclipse运行TestNG出现: CreateProcess error=206, ÎļþÃû»ò)չÃû的解决办法

    最近玩物流宝的一个项目,需要测试下3个系统打通的接口. 不测不要紧,一测吓一跳.我的乖乖:几百个bean被加进来.就凭我这肉机,内存不爆才怪. 于是换一套方案,用了另一个测试接口. 但是这个测试接口, ...