共计 1740 个字符,预计需要花费 5 分钟才能阅读完成。
前言
家喻户晓,JavaScript 是单线程的,然而不可避免的,JavaScript 也须要进行一些异步工作,比方上面这个例子
function foo() {console.log("first");
setTimeout((function(){console.log( 'second');
}),5);
}
for (var i = 0; i < 1000000; i++) {foo();
}
复制代码
下面这个例子,执行后果会首先全副输入 first,而后全副输入 second,而不是交替执行
在这个过程中,很显著产生了并发的异步工作,那么问题来了,单线程的 JavaScript 是怎么实现异步的?
JavaScript 为什么是单线程的?
作为一个 Java 程序员,在晓得了 JavaScript 是单线程之后,首先的反馈就是不解,为什么一种语言会被设计成单线程的呢? 它为什么不能应用多线程来提高效率呢?
JavaScript 的单线程,与它的用处无关。作为浏览器脚本语言,JavaScript 的主要用途是与用户互动,以及操作 DOM。这决定了它只能是单线程,否则会带来很简单的同步问题。比方,假设 JavaScript 同时有两个线程,一个线程在某个 DOM 节点上增加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
所以,为了防止复杂性,从一诞生,JavaScript 就是单线程,这曾经成了这门语言的外围特色,未来也不会扭转。
JavaScript 怎么实现异步?
当初咱们曾经理解了 JavaScript 为什么是单线程的了,那么它又是怎么实现异步的呢?
JavaScript 的异步能力次要是由运行环境提供的
JavaScript 的运行环境
JavaScript Runtime 也就是 JavaScript 代码运行的中央。比方 JavaScript 能够在 chrome 中执行,也能够在 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 也能够执行异步工作。
最初
如果你感觉此文对你有一丁点帮忙,点个赞。或者能够退出我的开发交换群:1025263163 互相学习,咱们会有业余的技术答疑解惑
如果你感觉这篇文章对你有点用的话,麻烦请给咱们的开源我的项目点点 star:http://github.crmeb.net/u/defu 不胜感激!
残缺源码下载地址:https://market.cloud.tencent….
PHP 学习手册:https://doc.crmeb.com
技术交换论坛:https://q.crmeb.com