foreword
As we all know, it JavaScript
is single-threaded, but inevitably, JavaScript
some asynchronous tasks are also required, such as the following example
function foo() {
console.log("first");
setTimeout(( function(){
console.log( 'second' );
}),5);
}
for (var i = 0; i < 1000000; i++) {
foo();
}
复制代码
In the above example, the execution results will be output first first
, and then all output second
, instead of alternate execution.
In this process, it is obvious that concurrent asynchronous tasks have occurred, so the question JavaScript
is, how does a single thread achieve asynchronous?
JavaScript
Why is it single threaded?
As a Java
programmer, after knowing that it JavaScript
is single-threaded, the first reaction is to wonder why a language is designed to be single-threaded? Why can't it use multi-threading to improve efficiency?
JavaScript
is single-threaded, relative to its purpose. As a browser scripting language, JavaScript
the main use is to interact with the user, as well as to operate DOM
. This determines that it can only be a single thread, otherwise it will bring complex synchronization problems. For example, suppose JavaScript
there are two threads at the same time, one thread DOM
adds content to a certain node, and the other thread deletes this node, which thread should the browser take?
So, in order to avoid complexity, from the very beginning, JavaScript
it is single-threaded, which has become a core feature of this language and will not change in the future.
JavaScript
How to achieve asynchrony?
Now that we have understood JavaScript
why it is single-threaded, how does it achieve asynchronous?
JavaScript
The asynchronous capability is mainly provided by the running environment
JavaScript
operating environment
JavaScript Runtime
That is where the JavaScript
code runs. For example , it can beJavaScript
executed in , it can also be executed in , and bothchrome
node
chrome
node
JavaScript Runtime
由上图可知,JavaScript Runtime
主要包括Js Engine
与WebAPI
等内容
Js Engine
将我们编写的 JavaScript
转换为更高效的机器码,以实现更好的性能。
chrome
浏览器中的 JavaScript
由 V8
引擎处理。V8
引擎主要包括内存堆与执行栈两个部分
- 内存堆:用于分配
JavaScript
程序使用的内存。 - 执行栈:在执行栈中,您的
JS
代码被读取并逐行执行。
除了引擎,JavaScript Runtime
也提供了WebAPI
供JS
代码调用,WebAPI
提供了网络请求,定时器,事件监听等多种能力
因为JS Runtime
并不是单线程的,而是持有一个线程池,因此WebAPI
中的代码是运行在其他线程的,自然也就提供了异步的能力
事件循环机制
JS
分为同步任务和异步任务,同步任务都在主线程上执行,形成一个执行栈- 栈中的代码调用
WebAPI
时也就异步任务,异步任务执行完成后,它们会在事件队列中添加各种事件 - 而栈中的代码执行完毕,就会读取事件队列中的事件,去执行那些回调
- 执行栈与任务队列如此循环,也就是事件循环机制
需要注意的是,一旦执行栈中的所有同步任务执行完毕(此时JS
引擎空闲),系统就会读取任务队列,将可运行的异步任务添加到可执行栈中
因此setTimeout
设置的时间并不是准确的,可能在它推入到事件列表时,主线程还不空闲,正在执行其它代码,因此存在误差。
总结
JavaScript
本质上是运行在浏览器里的脚本语言,为了简单与避免操作DOM
时引入同步问题,所以JavaScript
被设计成了单线程的语言。
JavaScript
的异步能力是由运行环境提供的,通过WebAPI
与事件循环机制,单线程的JS
也可以执行异步任务。
参考资料
JavaScript 运行机制详解:再谈Event Loop
从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理
Javascript — single threaded, non-blocking, asynchronous, concurrent language