¿Cómo logra la asincronía JavaScript de subproceso único?

prefacio

Como todos sabemos, JavaScriptes de un solo subproceso, pero inevitablemente, JavaScripttambién se requieren algunas tareas asincrónicas, como el siguiente ejemplo.

function foo() {
    console.log("first");
    setTimeout(( function(){
        console.log( 'second' );
    }),5);
}
 
for (var i = 0; i < 1000000; i++) {
    foo();
}
复制代码

En el ejemplo anterior, los resultados de la ejecución se mostrarán primero firsty luego todos los resultados second, en lugar de una ejecución alternativa.
En este proceso, es obvio que se han producido tareas asincrónicas concurrentes, por lo que la pregunta JavaScriptes, ¿cómo logra un único subproceso asincrónico?

JavaScript¿Por qué es de un solo hilo?

Como Javaprogramador, después de saber que JavaScriptes de un solo subproceso, la primera reacción es preguntarse por qué un lenguaje está diseñado para ser de un solo subproceso ¿Por qué no puede usar subprocesos múltiples para mejorar la eficiencia?

JavaScriptes de un solo subproceso, en relación con su propósito. Como lenguaje de scripting del navegador, JavaScriptel uso principal es para interactuar con el usuario, así como para operar DOM. Esto determina que solo puede ser un único hilo, de lo contrario traerá problemas complejos de sincronización. Por ejemplo, suponga JavaScriptque hay dos subprocesos al mismo tiempo, un subproceso DOMagrega contenido a un nodo y el otro subproceso elimina este nodo, ¿qué subproceso debe tomar el navegador?

Entonces, para evitar la complejidad, desde el principio, JavaScriptes de un solo subproceso, lo que se ha convertido en una característica central de este lenguaje y no cambiará en el futuro.

JavaScript¿Cómo lograr la asincronía?

Ahora que hemos entendido JavaScriptpor qué es de un solo subproceso, ¿cómo logra la capacidad asíncrona?
JavaScriptLa capacidad asíncrona la proporciona principalmente el entorno de ejecución .

JavaScriptentorno operativo

JavaScript RuntimeAhí es donde se JavaScriptejecuta el código. Por ejemplo , se puedeJavaScript ejecutar en , también se puede ejecutar en , y amboschromenodechromenodeJavaScript 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

Supongo que te gusta

Origin juejin.im/post/7083286147920560158
Recomendado
Clasificación