简述
大家都听过v8引擎的概念,js 是单线程的,或是使用回调队列。
js引擎
最流行的是谷歌的 V8 引擎, V8 引擎使用在 Chrome 以及 Node 中。
引擎结构:
引擎由两部分组成:
- 内存堆:内存分配发生的地方
- 调用栈:代码执行时的地方
运行时
有些浏览器的 API 经常被使用到(比如说:setTimeout),但是,这些 API 却不是引擎提供的。
有很多引擎之外的 API,我们把这些称为浏览器提供的 Web API,比如说 DOM、AJAX、setTimeout等等。
调用栈
JavaScript 是一门单线程的语言,这意味着它只有一个调用栈,因此,同一时间只能做一件事。调用栈记录了我们在程序中的位置。如果我们运行到一个函数,它就会将其放置到栈顶。当从这个函数返回的时候,就会将这个函数从栈顶弹出。
举个例子
function add(x,v){
return x+y;
}
function printDouble(x){
let s = add(x,x);
console.log(s);
}
printDoble(2);
程序开始执行,调用栈为空
每一个进入调用栈的都称为调用帧。
观察下列代码,可知当异常发生的时候堆栈追踪是怎么被构造的,堆栈的状态是如何的。
function foo() {
throw new Error('SessionStack will help you resolve crashes :)');
}
function bar() {
foo();
}
function start() {
bar();
}
start();
当达到调用栈最大的大小的时候会发生堆栈溢出。
function foo() {
foo();
}
foo();
这是一个递归函数,没有任何终止条件。每执行一步就会将相同函数加入调用堆栈中。like this
可看出,总会在某个节点发生溢出。浏览器报错如下:
单线程不用处理多线程环境出现复杂的情况。不会出现死锁,但单线程也有一定的限制,由于只有一个调用堆栈。调用栈中的函数调用需要大量的时间来处理,若在浏览器进行大量复杂图片转码,当调用栈有函数要执行,浏览器就不能做任何事,它会被堵塞住。这意味着浏览器不能渲染,不能运行其他的代码,它被卡住了。造成UI不流畅。一旦你的浏览器开始处理调用栈中的众多任务,它可能会停止响应相当长一段时间。大多数浏览器都会这么做,报一个错误,询问你是否想终止 web 页面。
在不阻塞 UI 的情况下执行复杂的代码,让浏览器不会不响应。解决方案就是异步回调。在日常编写代码中要多注意代码的优化。