JS本质是单线程的。也就是说,它不能像JAVA语言那样,两个线程并发执行。

但是我们平时看到的JS,又是可以同时运作很多任务的,那究竟是怎么回事呢?

首先,JS 的代码,大致分为两类同步代码异步代码

console.log(1)
console.log(2)
console.log(3)

这就是典型的同步代码,编写顺序就是执行顺序

JS引擎的主线程负责执行代码,由于只有这一个线程,执行当然是同步的,即按照顺序来。

另外,还有一个叫做任务队列的东西,所有的异步代码都是从队列当中来。

所以实际上我们会发现,JS根本不可能同时执行两个任务,本质上还是单线程

在JS中,所谓的异步任务,有三种:

第一, 鼠标键盘事件触发,例如onclick、onkeydown等等

第二, 网络事件触发,例如onload、onerror等等

第三, 定时器,例如setTimeout、setInterval

因为这些任务的发生都不是在当下,而是过段时间以后再执行。因此时间不可控,你不能因为5秒后要执行一个函数,就让主线程闲置5秒什么都不干吧?所以你只能继续执行后续的同步代码。而当你单击鼠标或滚动窗口时,主线程可能正在执行其它代码,忙着呢!没工夫处理,因此,事件触发线程就负责来接收这个事件,并把要执行的任务暂时保存在任务队列当中。等主线程把手里的同步代码执行完,就立刻会向任务队列提取最新的任务。

这也就解释了为什么我们总把JS的异步函数叫做回调了,因为真的不是马上执行,而是回头再调的!

我们来看一个简单的例子:

setTimeout("console.log(2)", 0)
console.log(1)

反复执行这段代码,结果都是先打印1再打印2