How does single-threaded JavaScript achieve asynchrony?

foreword

As we all know, it JavaScriptis single-threaded, but inevitably, JavaScriptsome 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 JavaScriptis, how does a single thread achieve asynchronous?

JavaScriptWhy is it single threaded?

As a Javaprogrammer, after knowing that it JavaScriptis 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?

JavaScriptis single-threaded, relative to its purpose. As a browser scripting language, JavaScriptthe 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 JavaScriptthere are two threads at the same time, one thread DOMadds 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, JavaScriptit is single-threaded, which has become a core feature of this language and will not change in the future.

JavaScriptHow to achieve asynchrony?

Now that we have understood JavaScriptwhy it is single-threaded, how does it achieve asynchronous?
JavaScriptThe asynchronous capability is mainly provided by the running environment

JavaScriptoperating environment

JavaScript RuntimeThat is where the JavaScriptcode runs. For example , it can beJavaScript executed in , it can also be executed in , and bothchromenodechromenodeJavaScript Runtime

由上图可知,JavaScript Runtime主要包括Js EngineWebAPI等内容
Js Engine将我们编写的 JavaScript 转换为更高效的机器码,以实现更好的性能。
chrome 浏览器中的 JavaScriptV8 引擎处理。V8引擎主要包括内存堆与执行栈两个部分

  • 内存堆:用于分配 JavaScript 程序使用的内存。
  • 执行栈:在执行栈中,您的 JS 代码被读取并逐行执行。

除了引擎,JavaScript Runtime也提供了WebAPIJS代码调用,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

Guess you like

Origin juejin.im/post/7083286147920560158