大话javascript 4期:事件循环(1)

3次阅读

共计 2484 个字符,预计需要花费 7 分钟才能阅读完成。

一、进程与线程
现代操作系统比如 Mac OS X,UNIX,Linux,Windows 等,都是支持“多任务”的操作系统。
什么叫“多任务”呢?简单地说,就是操作系统可以同时运行多个任务。打个比方,你一边在用浏览器上网,一边在听 MP3,一边在用 Word 赶作业,这就是多任务,至少同时有 3 个任务正在运行。还有很多任务悄悄地在后台同时运行着,只是桌面上没有显示而已。
现在,多核 CPU 已经非常普及了,但是,即使过去的单核 CPU,也可以执行多任务。由于 CPU 执行代码都是顺序执行的,那么,单核 CPU 是怎么执行多任务的呢?
答案就是操作系统轮流让各个任务交替执行,任务 1 执行 0.01 秒,切换到任务 2,任务 2 执行 0.01 秒,再切换到任务 3,执行 0.01 秒……这样反复执行下去。表面上看,每个任务都是交替执行的,但是,由于 CPU 的执行速度实在是太快了,我们感觉就像所有任务都在同时执行一样。
真正的并行执行多任务只能在多核 CPU 上实现,但是,由于任务数量远远多于 CPU 的核心数量,所以,操作系统也会自动把很多任务轮流调度到每个核心上执行。
对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程,打开一个 Word 就启动了一个 Word 进程。
有些进程还不止同时干一件事,比如 Word,它可以同时进行打字、拼写检查、打印等事情。在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程(Thread)。
由于每个进程至少要干一件事,所以,一个进程至少有一个线程。当然,像 Word 这种复杂的进程可以有多个线程,多个线程可以同时执行,多线程的执行方式和多进程是一样的,也是由操作系统在多个线程之间快速切换,让每个线程都短暂地交替运行,看起来就像同时执行一样。当然,真正地同时执行多线程需要多核 CPU 才可能实现。
如果我们要同时执行多个任务怎么办?
有两种解决方案:
一种是启动多个进程,每个进程虽然只有一个线程,但多个进程可以一块执行多个任务。
还有一种方法是启动一个进程,在一个进程内启动多个线程,这样,多个线程也可以一块执行多个任务。
当然还有第三种方法,就是启动多个进程,每个进程再启动多个线程,这样同时执行的任务就更多了,当然这种模型更复杂,实际很少采用。
总结一下就是,多任务的实现有 3 种方式:

多进程模式;
多线程模式;
多进程 + 多线程模式。

同时执行多个任务通常各个任务之间并不是没有关联的,而是需要相互通信和协调,有时,任务 1 必须暂停等待任务 2 完成后才能继续执行,有时,任务 3 和任务 4 又不能同时执行,所以,多进程和多线程的程序的复杂度要远远高于我们前面写的单进程单线程的程序。
因为复杂度高,调试困难,所以,不是迫不得已,我们也不想编写多任务。但是,有很多时候,没有多任务还真不行。想想在电脑上看电影,就必须由一个线程播放视频,另一个线程播放音频,否则,单线程实现的话就只能先把视频播放完再播放音频,或者先把音频播放完再播放视频,这显然是不行的。
总结:1) 进程是 cpu 资源分配的最小单位(是能拥有资源和独立运行的最小单位)2) 线程是 cpu 调度的最小单位(线程是建立在进程的基础上的一次程序运行单位,一个进程中可以有多个线程)
二、浏览器是多进程的
浏览器包含哪些进程
1) Browser 进程:浏览器的主进程(负责协调、主控),只有一个。作用有

负责浏览器界面显示,与用户交互。如前进,后退等
负责各个页面的管理,创建和销毁其他进程
将 Renderer 进程得到的内存中的 Bitmap,绘制到用户界面上
网络资源的管理,下载等

2) 第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建 3) GPU 进程:最多一个,用于 3D 绘制等 4) 浏览器渲染进程(浏览器内核)(Renderer 进程,内部是多线程的):默认每个 Tab 页面一个进程,互不影响。主要作用为
页面渲染,脚本执行,事件处理等
关于浏览器进程问题可以简单基础三点:
1) 浏览器是多进程的。2) 浏览器之所以能够运行,是因为系统给它的进程分配了资源(cpu、内存)。3) 简单点理解,每打开一个 Tab 页,就相当于创建了一个独立的浏览器进程。
平时 coding 接触到最多的一个浏览器进程是浏览器渲染进程(浏览器内核), 它管理着页面渲染。脚本执行,事件处理等。要同时处理这么多事情,渲染进程显然是多线程的,它主要包括以下 5 个常驻线程:

GUI 渲染线程,负责渲染浏览器界面,解析 HTML,CSS,构建 DOM 树和 RenderObject 树,布局和绘制等。

JS 引擎线程,也称为 JS 内核,负责处理 Javascript 脚本程序,(例如 V8 引擎)。
事件触发线程,用来控制事件循环(可以理解为,JS 引擎线程自己都忙不过来,需要浏览器另开线程协助)。
定时触发器线程,浏览器定时计数器并不是由 JavaScript 引擎计数的,(因为 JavaScript 引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确),JS 中常用的 setInterval 和 setTimeout 就归这个线程管理。
异步 http 请求线程,也就是 ajax 发出 http 请求后,接收响应、检测状态变更等都是这个线程管理的。

三、Javascript 是单线程的
我们常说的 JavaScript 是单线程的,其实就是说的 JS 引擎是单线程的,它仅仅是浏览器渲染进程种的一个线程。为什么呢?因为 JavaScript 的主要作用是与用户互动,以及操作 DOM,如果 JavaScript 有两个线程,一个线程对一个 DOM 节点执行 A 操作,另一个线程这个 DOM 节点执行 B 操作,那么就会起冲突,所以 JavaScript 在前端的应用就注定了它是单线程的。
然而 JavaScript 的单线程特性就注定我们不用它去完成密集的 cpu 运算,因为密集 cpu 运算耗时过长,阻塞页面渲染。为了解决这个问题,HTML5 提出 Web Worker 标准,允许 JavaScript 脚本创建多个线程,但是子线程完全受主线程控制,且不得操作 DOM。

正文完
 0