五个线程
js引擎线程
: 执行js
代码
GUI线程
: 绘制用户界面
http网络请求线程
: 处理网络请求, 等请求返回之后, 将回调函数放进事件队列中
定时器触发线程
: 定时器等待事件结束之后, 将回调函数放进事件队列中
浏览器事件处理线程
: click
, mouse
等事件触发, 将回调函数放进事件队列
js引擎线程
和GUI线程
的运行状态是互斥的, 即 当js引擎线程
在执行的时候, 它可能会改变DOM
元素, 进而影响到GUI
的渲染结果, 所以此时GUI
线程是冻结的。最明显的例子是, 当js代码进入死循环的时候, 用户是无法跟界面进行交互的。
js
引擎是单线程的, 同一时间只能做一件事。
function foo() {
var a = 10
function bar() {
console.log(a)
}
bar()
}
foo()
这是同步代码, 上面的代码在执行的时候, 经历了一下几个阶段
- 预编译阶段, 执行栈为空
-
foo
执行, 创建一个执行帧,包含参数列表局部变量等等, 将这一帧压入栈中 - 执行
foo
内部代码, 执行bar
函数 - 创建
bar
的执行帧, 包含参数列表,局部变量等, 压入栈中 - 打印
a
的值,bar
执行完毕, 此帧从执行栈中弹出 -
foo
函数执行完毕,foo
的帧从栈中弹出 - 执行栈为空
$ajax({
url: 'http://www.example.com?a=1&b=2',
method: 'get',
data: {},
success: function(res){
console.log(res)
}
})
console.log(111)
-
ajax
进入Event Table
- 打印
111
-
ajax
事件完成http
网络请求把任务放进事件队列 - 主线程读取任务执行回调函数
setTimeout 并不准确
js
任务在被读取到的时候, 都会进入一个叫做执行栈的地方。
然后会判断这个任务是同步任务还是异步任务
异步任务会进入 事件表中, 注册回调函数之后,放进任务队列里面
同步任务会交给js主线程立即执行,同步任务执行完毕之后, 读取任务队列里面的异步任务执行。
js
引擎会一直检测主线程是否为空, 一旦为空, 就去看任务队列里面有没有任务需要执行。
所以如果有一个同步任务, 去跑一万次循环, 同时有一个异步任务, 30ms
之后打印一句话, 那么肯定会出问题
function foo(times) {
for (var i = 0; i < times; i++){
console.log(i);
}
}
var start = + new Date()
foo(100000)
console.log('timeout start: ' + start);
setTimeout(()=>{
console.log('timeout end');
console.log(+ new Date() - start);
}, 30)
当疯狂的打印完 100000
次之后, 时间已经过去了 600+ ms

网友评论