- js引擎线程
-
- (解释执行js代码、用户输入、网络请求)
- GUI线程
-
- (绘制用户界面、与js主线程是互斥的)
- http网络请求线程
-
- (处理用户的get、post等请求,等返回结果后将回调函数推入任务队列)
- 定时触发器线程
-
- (setTimeout、setInterval等待时间结束后把执行函数推入任务队列中)
- 浏览器事件处理线程
-
- (将click、mouse等交互事件发生后将这些事件放入事件队列中)
UI主线程负责协调运转
JS引擎线程和GUI线程-互斥
- JS可以操作DOM元素,进而会影响到GUI的渲染结果,因此JS引擎线程与GUI渲染线程是互斥的。
- 也就是说当JS引擎线程处于运行状态时,GUI渲染线程将处于冻结状态。
Js执行机制-单线程
- 单线程-同一时间只能做一件事
Js执行机制-多线程不好吗?
js设计出来就是为了与用户交互,处理DOM。
假如js是多线程,同一时间一个线程想要修改DOM,另一个线程想要删除DOM,问题就变得复杂许多,浏览器不知道听谁的,如果引入“锁”的机制,这不就又回到了其他语言尴尬的困境了吗。
大量数据操作怎么办?
单线程计算能力有限,大量数据需要计算渲染的话,我们可以配合后端进行操作
比如VUE与nodejs配合,也就是传说中的SSR技术。
Js执行机制
JavaScript是基于单线程运行的,同时又是可以异步执行的。
一般来说这种既是单线程又是异步的语言都是基于事件来驱动的。
恰好浏览器就给JavaScript提供了这么一个环境。
用文字描述上图:
同步和异步任务分别进入不同的执行"场所",
- 同步的进入主线程,
- 异步的进入Event Table并注册函数。
当指定的事情完成时,Event Table会将这个函数移入Event Queue。
主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。
上述过程会不断重复,也就是常说的Event Loop(事件循环)。
同步任务
function outer (ot) {
function inner (it) {
console.log(it);
}
inner(20);
console.log(ot);
}
outer(10);
0.代码没有执行的时候,执行栈为空栈
1.outer函数执行时,创建了一帧,这帧中包含了形参、局部变量(预编译过程),然后把这一帧压入栈中
2.然后执行outer函数内代码,执行inner函数
3.创建新帧,同样有形参、局部变量,压入栈中
4.inner函数执行完毕,弹出栈
5.outer函数执行完毕,弹出栈
6.执行栈为空
执行栈其实相当于js主线程
异步任务
$.ajax({
url: 'localhost:/js/demo.json',
data: {},
success: function (data) {
console.log(data);
}
});
console.log('run');
- Ajax 进入Event Table,注册回调函数success
- 执行console.log('run');
- ajax事件完成, http网络请求线程把任务放入Event Queue中
- 主线程(调用栈)读取任务下执行success函数
换一张图理解一下
Js执行机制-单线程
\
用定时器举个栗子
重新理解定时器
setTimeout的等待时间结束后并不是直接执行的,而是先推入浏览器的一个任务队列,在同步队列结束后再依次调用任务队列中的任务。
setTimeout(function(){}, 0)
Js主线程中的执行栈为空时,0毫秒实际上也达不到的,根据HTML标准,最低4毫秒。
setInterval是每隔一段时间把任务放到Event Queue之中
例子
function test (num) {
for (var i = 0; i < num; i++) {
console.log(i);
}
}
setTimeout(function () {console.log('time')}, 0);
test(2);
console.log('hello world');
// 输出
0
1
hello world
time
真正了解底层原理,才能是持续化发展之路!