JS是单线程的,但浏览器是多进程多线程的
这里的JS线程指的是JavaScript引擎(如V8引擎),浏览器一般包含多个进程:浏览进程、渲染进程、插件进程,每个tab页都有独立的进程。
渲染进程一般包含多个线程:
JS引擎线程(主线程)、
GUI渲染线程(解析HTM、CSS,与JS引擎线程互斥)
HTTP网络请求线程(一般由JS线程触发)
定时器触发线程(setTimeout、setInterval所在的线程,并不是js线程记时)
浏览器事件处理线程
其中js线程与GUI线程是互斥的。
JS引擎线程主要管理内存分配、执行调用栈
JavaScript 只是一个单线程的编程语言,这意味着它只有一个调用栈。这样它只能一次做一件事情。
调用栈是一种数据结构,里面会记录我们在程序中的大概位置。当执行进入一个函数,把它置于栈的顶部。如果从函数中返回则从栈顶部移除函数。这就是调用栈所能够做的事情。
1 function multiply(x, y) { 2 return x * y; 3 } 4 5 function printSquare(x) { 6 var s = multiply(x, x); 7 console.log(s); 8 } 9 10 printSquare(5);
执行栈:
发生异常时,正好追踪异常是如何构造出来的,基本就是打印出当前调用栈的状态即可。
‘堆栈溢出’--当达到调用栈的上限时,就会发生堆栈溢出。递归代码,条件设置不当时,容易发生堆栈溢出。
事件循环
JS是单线程的,且只有一个执行栈。为了更好的处理用户交互,所有浏览器都内置了一种被成为事件循环(event loop)的处理机制。
事件循环只有一项简单的工作-监测调用栈和回调队列。如果调用栈是空的(JS引擎空闲时),它会从回调队列中取得第一个事件然后入栈,并有效地执行该事件。
打个比方,当 JavaScript 程序发起 Ajax 请求来从服务器获得数据,你在回调函数中书写 "response" 代码,JS 引擎会告诉宿主环境:
"嘿,我现在要挂起执行了,现在当你完成网络请求的时候且返回了数据,请执行回调函数。"
HTTP网络请求线程、定时器触发线程、浏览器事件处理线程都会在事件返回或到达时间后,向回调队列添加回调事件。