浅谈JS中的异步和单线程

为什么js引擎是单线程的?html

假如js引擎为多线程,DOM操做可能很容易会出现混乱错误的状况:好比某个时刻a线程要操做a节点时,线程b在时刻a以前已将a节点删除了,这时便会出问题。ajax

异步能够避免主线程阻塞,因此对于耗时/不肯定的操做,使用异步是很好的选择。常见的有:处理ajax请求的线程、处理DOM事件的线程、定时器线程、读写文件的线程等。segmentfault

异步线程执行完毕后,会通知主线程执行相应的回调函数,这个通知机制的实现,以下:bash

消息(任务)队列与事件循环(event loop)

  • 消息队列:消息队列是一个先进先出的队列,它里面存放着各类消息。
  • 事件循环:事件循环是指主线程重复从消息队列中取消息、执行的过程。

实际上,主线程只会作一件事情,就是从消息队列里面取消息、执行消息,再取消息、再执行。当消息队列为空时,就会等待直到消息队列变成非空。并且主线程只有在将当前的消息执行完成后,才会去取下一个消息。这种机制就叫作事件循环机制,取一个消息并执行的过程叫作一次循环。数据结构

"任务队列"中的事件,除了IO设备的事件之外,还包括一些用户产生的事件(好比鼠标点击、页面滚动等等)。只要指定过回调函数,这些事件发生时就会进入"任务队列",等待主线程读取。多线程

"任务队列"是一个先进先出的数据结构,排在前面的事件,优先被主线程读取。主线程的读取过程基本上是自动的,只要执行栈一清空,"任务队列"上第一位的事件就自动进入主线程。可是,因为存在"定时器"功能,主线程首先要检查一下执行时间,某些事件只有到了规定的时间,才能返回主线程。异步

将逻辑用代码表示:

while(true) {
    var message = queue.get();
    execute(message);
}
复制代码

消息队列中的消息具体是什么呢?消息的具体结构是与具体的实现相关的,可是为了简单起见,咱们能够认为:函数

消息就是注册异步任务时添加的回调函数。(多是不对的)
复制代码

从生产者与消费者的角度看,异步过程是这样的:oop

  • 异步线程是生产者,主线程是消费者(只有一个消费者)。异步线程执行异步任务,执行完成后把对应的回调函数封装成一条消息放到消息队列中;主线程不断地从消息队列中取消息并执行,当消息队列空时主线程阻塞,直到消息队列再次非空。

同步能够保证顺序一致,可是容易致使阻塞;异步能够解决阻塞问题,可是会改变顺序性。spa

参考文献

JavaScript:完全理解同步、异步和事件循环(Event Loop)

JavaScript 运行机制详解:再谈Event Loop

相关文章
相关标签/搜索