js单线程执行异步任务的原理

180 阅读3分钟

javaScript 作为浏览器的脚本语言之一,最大的特性就是单线程,既然javaScript是单线程,但又同时可以进行异步操作,这是为啥呢?

js是单线程,这句话没错。但确切的说js是只有一个主线程,但是其实它还有一些其他线程的,当然所有函数任务只可以在主线程执行。

js作为浏览器的脚本,其最根本的作用就是实现用户与浏览器的交互行为,当一个用户要删除一个A,又同时向A中添加内容的时候,若是多线程,应该怎么样去处理? 没有办法处理,若是单线程就跟简单了,用户先执行那个操作,我们的主线程就进行哪一个,不会出现任何冲突。

那么js明明是单线程,但又同时可以进行异步操作,是如何做到的呢?

首先我们要明确一个概念,那就是任务队列,单线程只有上一个任务结束了,才能执行下一个任务,所以就会面临一个问题,比如当我们使用Ajax读取网络数据,会消耗大量的时间,但是又不得不等着结果出来,再往下执行。所以js语言的设计者意识到,这时主线程完全可以不管IO设备(输入输出设备,入Ajax等),挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回头,把挂起的任务继续执行下去。

于是呢,任务就被分成两种,一种是同步任务,一种是异步任务。

  • 同步任务:只有上一个任务执行完成后,才可以执行下一个任务,在主线程中。
  • 异步任务:这个队列的所有任务都是不进入主线程执行,而是被浏览提供给线程执行,当执行完毕后就会产生一个回调函数,并且通知主线程,在主线程执行完当前所执行的任务后,就会调取最早通知自己的回调函数,使其进入主线程中执行,比如Ajax请求,在主线程中呈现的就是请求结果。

同步异步之间的协同

  1. 所有同步任务都在主线程上执行,形成一个执行栈。
  2. 主线程之外,还存在一个任务队列。只要异步任务有了运行结果,就在任务队列之中放置一个事件(回调函数callback)
  3. 一旦执行栈中所有同步任务执行完毕,系统就会读取任务队列,看看里面有哪些事件。那些对应的异步任务,于是结束了等待状态,进入执行栈,开始执行(循环执行这一步)。

所谓的回调函数,就是那些会被主线程挂起来的代码,一步任务必须指定回调函数,当主线程开始执行异步任务,就是执行对应的回调函数。

这就是我们常说的单线程与一步是必须要依赖于浏览器的