单线程
我们常说“JavaScript是单线程的”。
所谓单线程,是指在JS引擎中负责解释和执行JavaScript代码的线程只有一个。不妨叫它 主线程。
但是实际上还存在其他的线程。例如:处理AJAX请求的线程、处理DOM事件的线程、定时器线程、读写文件的线程(例如在Node.js中)等等。这些线程可能存在于JS引擎之内,也可能存在于JS引擎之外,在此我们不做区分。不妨叫它们 工作线程。
同步与异步
同步(Sync): 如果在调用函数的时候,当这个函数返回时,你已经拿到了预期的结果,那么这个函数就是同步的。
1 | console.log('Hello, world!'); |
在一些主流的语言比如说C, C++, Java, Python 等,大部分情况下都是同步程序。即使在进行网络访问的时候。
1 | User user = client.getUser('Bob'); |
异步(Async): 如果在调用函数的时候,当这个函数返回时,你并不能拿到你想要的结果,而且需要在将来通过一定的方法获得,那么这个函数就是异步的。
1 | fs.readFile('foo.txt', 'utf8', function(err, data) { |
异步在java中也有使用。
1 | Feature<User> featureUser = asyncClient.getUser('Bob'); |
异步的执行过程
主线程发起一个异步请求,相应的工作线程接收请求并告知主线程已收到(异步函数返回);主线程可以继续执行后面的代码,同时工作线程执行异步任务;工作线程完成工作后,通知主线程;主线程收到通知后,执行一定的动作(调用回调函数)。
在Javascript中,通知主线程是由消息队列和事件循环(Event Loop)完成的。
1 | 工作线程将回调函数放到消息队列,主线程通过事件循环过程去取回调函数。 |
事件循环
之所以称之为事件循环,是因为它经常按照类似如下的方式来被实现:1
2
3while (queue.waitForMessage()) {
queue.processNextMessage();
}
如果当前没有任何消息,queue.waitForMessage() 会同步地等待消息到达。
值得一提的是事件循环中取得的消息将会被同步的执行,每一个消息完整的执行后,其它消息才会被执行。