进程 线程 同步 异步
1.进程与线程
进程是一个动态的过程,是一个活动的实体。简单来说一个应用程序的运算就可以被看做一个进程。
线程是运行中的实际的任务执行者,可以说进程中包含多个可以同时运行的线程。
JavaScript语言的一大特点就是单线程也就是说同一个时间只能做一件事。(为什么JS不能有多个线程?)
JavaScript的单线程,与它的用途有关系。作为浏览器的及脚本语言“JS主要作用是遇用户互动,操作DOM”,这就决定了它只能是单线程的,否则会带来很复杂的同步问题“例如:一个线程在有个DOM节点上添加内容,又在线程上删除这个节点,这时浏览器应该以哪个线程为准?”
为了利用多核UPU的计算能力,HTML提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程的控制,且不得操作DOM。所以这个新标准并没有改变JavaScript单线程的本质。
2.同步与异步
- 单线程就意味着,所有的任务需要排队,前一个任务结束才会执行下一个任务。如果前一个任务耗时很长,后一个任务就等着。
- 如果排队是因为计算过大“CPU忙不过来”,就算了。但是很多时候CPU是闲着的,因为IO设备“输入输出设备”很慢“比如AJAX操作从网络读取数据”,不得不等着结果出来再往下执行。
- JavaScript语言的设计者意识到上面的问题,这时候就让主线程完全不管IO设备,把它挂起来“等待中的任务”,先运行后面排队的任务,等到IO设备返回了结果再回过头把挂起来的任务继续执行下去。
- 所以,所有的任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(Asynchronous)。
- 同步在主线程上排队执行的任务,只有前一个执行完毕,才能执行后一个任务。 按照顺序执行,阻塞的。
- 异步异步任务不进入主线程,而进入“任务队列(task queue)”的任务,只有“任务队列”通知主线程,某个异步任务可以执行了,这个任务才会进入主线程。
使用异步的场景
- 定时任务 : setTimeout,setInterval
- 网络请求 : ajax请求,动态img添加
- 事件绑定 :点击等交互事件
3.任务队列
异步任务运行机制:
- 所有同步任务都在主线程上执行,形成一个执行线。
- 主线程之外,还存在一个“任务队列”,只要异步操作执行完成,就到任务队列中排队。
- 一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。
- 主线程不断重复上面的第三步。(主线程从任务队列中读取事件,这个过程是循环不断的,所以整个这种运行机制又称为Event Loop“事件循环”)。
4.事件和回调函数
- 任务队列是一个事件的队列(也可以理解成消息的队列),IO设置完成一项任务就在任务队列中添加一个事件,表示相关的异步任务可以进入到“执行栈”中,主线程读取“任务队列”就是读取里面有哪儿些事件。
- 任务队列中的事件,除了IO设备的时间以外,还包括一些用户产生的事件(比如鼠标单击,页面滚动等)。只要制定过回调函数,这些事件发生时就会进入“任务队列”等待主线程读取。
- 回调函数(callback),就是那些会被主线程挂起来的代码,异步任务必须执行回调函数,当主线程开始执行异步任务,就是执行对应的回调函数。
- 任务队列是一个先进先出的数据结构,排在前面的事件,优先被主线程读取,主线程的读取过程基本上是自动的,只要执行栈已清空,“任务队列”的第一位的时间就自动进入主线程。但是,由于存在后文提到的“定时器”功能,主线程首先要先检查一下执行事件,某些事件只有到了规定的时间才能返回主线程。
5.Event Loop
- 主线程从“任务队列”中读取事件,这个过程是循环不断的,所以整个的这种运行机制称为Event Loop “事件循环”。
6.微任务,宏任务
在事件中,没进行一次循环操作称为tick。分为宏任务(macrotask) 和微任务(microtask) 并且每次宏任务执行完毕,都要清空所有的微任务。
宏任务
setTimeout,setInterval, I/O 。UI交互事件
微任务
Promise等……
Author: 李金帅
Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.