最近在看JavaScript
的Generator
、Promise
等实现异步的方法。对于一直用Objective-C
编程的我来说,是有些云里雾里。故查了些资料,了解相关的内容,遂有此文。
为什么JavaScript
是单线程的语言
首先,我们要解释下,JS
是单线程的,并不是说JS
中只有一个线程,而是在JS
引擎中负责解释和执行JS
语句的线程只有一个,我们称之为主线程。
在JS
中,还是有很多其他线程存在的,比如:处理DOM事件的线程,定时器线程,IO线程等。
为什么JS
中只有一个线程呢? 这里要说下JS
诞生的背景,它是浏览器中执行脚本的语言,主要用途是和用户交互,为了提升体验,避免多线程带来的同步等问题,简化整个模型,采用了单线程。(Objective-C
也是为了交互而生,但是并没有采用单线程,而是支持多线程,我个人觉得这个更多是设计思想的选择,而JS
这样设计确实带来了更简单的模式)
在HTML5中,提出了Web Worker标准,允许JS创建多个线程,但是规定子线程受主线程控制,且不能操作DOM。
JS
任务管理
我们先看一张图,了解下JS
中是如何管理和执行任务的:
这里分为三个区域:
- 执行栈(主线程)
- 任务队列(其他线程)
- 堆 (对象)
主线程任务执行栈
主线程的任务使用栈来实现任务执行和调用,这里用栈是因为栈的结构方便实现函数调用顺序的管理。
这里简单举个例子:
|
|
栈中执行顺序就是
- funcA
- funcB
- console.log
任务队列
每当遇到需要异步执行的任务(请求网络、IO等),JS不会阻塞等待结果,而是往下面执行,当异步的任务执行了之后,系统发送通知出来,然后等待主线程任务栈执行完毕后,执行这些异步回调。
流程如图,就是所谓的Event Loop
注意,这里即使异步的任务很快执行完毕,也会等到执行栈中的任务执行完毕后,才执行,这里用setTimeout
来举个例子:
|
|
这里虽然延迟是0ms,但是输出依然是:
|
|
所以setTimeout等的延迟时间,其实是不准确的,如果主线程一直很忙,是不会执行到的。
堆
这里堆就是用来管理系统中的对象,大部分的语言应该都是使用堆来管理对象(我知道的),这里就不多解释。
总结
这篇文章主要是介绍了JS
为什么采用了单线程的思想,然后介绍了JS
中是如何任务管理是如何通过主线程+任务队列的方式来实现,从而实现了Event Loop
。