JavaScript 的异步机制

为什么 JavaScript 是单线程的

单线程的特点是同一时间只能做一件事。JavaScript 之所以采用这种方式主要跟它的用途有关,JavaScript 的用途主要是操作 DOM 与用户互动,如果采用多线程同时处理很多件任务,很可能导致用户收到的反馈与其进行的操作不符的情况,带来很复杂的同步问题。
但是为了利用多核 CPU 的计算能力,HTML5 提出 Web Worker标准,允许 JavaScript 创建多个线程,但是子线程完全受主线程控制,且不得操作 DOM。所以,这个标准并没有改变这门语言单线程的本质。

同步和异步的区别

一般操作分为两步:发出调用和得到结果。

这其中又分为两种情况:
发出调用,立即得到结果。
发出调用,不能立即得到结果,需要额外的操作才能得到结果。

同步是第一种情况,调用之后一直等待,直到返回结果。
异步属于第二种情况,调用之后不能立即得到结果,需要通过其他的一系列手段才能拿到结果,但是在发出调用到拿到结果之间的时间,可以介入其他的任务。

实现异步的方法

JS 是单线程的,但是 JS 的运行环境(浏览器)是支持多线程的。我们可以将 JS 引擎提供的线程称为主线程,运行环境提供的线程称为工作线程。需要注意的一点是,不论是同步任务还是异步任务,它们最终都要在主线程上执行。

  1. 首先,不管是同步任务和异步任务都会在主线程按序进行调用,只是异步任务还需要其它一系列的操作才能拿到结果,所以会进入工作线程,不会阻塞后面同步任务的执行,主线程首先会将同步任务依次执行完。
  2. 进入工作线程的异步任务在经过一定的操作后(IO操作完成,用户点击一次鼠标,Ajax完成,或一个图片加载完成等)会产生一个相应的事件(消息)加入到事件(消息)队列里。(事件队列/消息队列)
  3. 主线程执行完同步任务后会查看事件(消息)队列里是否有事件,如果有,就取回排在最前面的事件执行。主线程从工作线程取事件,执行事件的过程是循环重复的。(事件循环/Event Loop)

JS 始终只有一个线程,它还维护一个事件(消息)队列,当前函数栈执行完成后就去不断的读取事件(消息),取到了就执行。但是 JS 引擎只负责取事件(消息),不负责生产事件(消息)。
JS 运行时(运行环境)负责给 JS 引擎发送事件(信息)。JS 运行时负责生产事件(消息),不负责取事件(消息)。

本文参考:
【1】https://segmentfault.com/a/1190000004322358
【2】http://blog.csdn.net/lin_credible/article/details/40143961