理解Javascript的并发模型

62 阅读3分钟

前置问题

  • 进程和线程是什么,有什么关系吗?

  • 什么是单线程和多线程?

  • Javascript为什么是单线程?

  • 什么是任务队列?

进程和线程

进程指的是系统资源分配和调度的单元。一个运行的程序对应一个进程,一个进程包含运行中的程序和程序所使用到的内存和系统资源。

线程是进程下的执行者,一个进程至少开启一个线程,也可以有多个线程。

由于一个线程在同一个时间内只能处理一件事情,如果想要在同一时间内执行多件事情,就必须对应多个线程同时运行,由此并行的概念由此出现。与此关联的并发指的是在同一时间内多件事情可以交替的执行。其中需要注意的是,这段时间内有且仅有一件事在执行,例如单核CPU实现多任务运行的过程就是并发。

单线程和多线程

单线程指的是从头到尾,逐行执行,如果在执行的过程中出现问题,剩下的代码不会在执行,容易造成阻塞。 多线程代码运行的环境不同,各线程独立,互不影响避免阻塞。

javaScript之所以是单线程的原因,是因为其主要功能是与用户进行交互,以及操作DOM。例如同时有两个线程,一个线程在某个节点添加内容,另一个线程删除,这个时候浏览器该以哪一个进程为主呢?

注意: 需要注意的是,JavaScript 的单线程是指一个程序进程(在浏览器运行环境中运行的就是浏览器进程)中只有一个 JavaScript 的执行线程,同一时刻内只会有一段 JavaScript 代码在执行。而异步机制是运行环境的两个或以上常驻线程共同完成的。

任务队列

javascript中的程序可以分为两种: 同步任务(Synchronous):同步任务在主线程调用之后需要一直等待,只有当前任务执行完毕之后,才能执行下一个任务。 异步任务(Asynchronous):异步任务会在主线程执行一部分,然后退出主线程到专用线程中执行,在一步任务准备就绪之后,会被推进任务队列等待,当主线程空闲的时候,JS解释器会执行一次事件循环将事件队列中的首个事件推进主线程执行。 具体来说,异步执行的运行机制 如下:

  1. 所有同步任务及异步任务按照 编译原理 在主线程上执行,形成一个 执行上下文栈(Execution Context Stack)
  2. 同步任务执行完成并返回结果后退出执行上下文栈;异步任务执行一部分后,退出主线程的执行上下文栈,推进至运行环境的专用线程中继续执行
  3. 当运行环境的专用线程中的异步任务准备就绪后,将被推至任务队列(Task Queue)中等待执行
  4. 主线程的执行上下文栈中的所有任务执行完毕后,JavaScript 解释器就会通过事件循环机制检查任务队列中是否存在等待执行的事件。如果存在,则队首的异步任务将结束等待状态,进入执行上下文执行
  5. JavaScript 主线程运行期间将不断重复上面第四步