随着js愈来愈流行,团队利用其在更多领域的堆栈,前端,后端,混合app,嵌入设备等。 这篇文章旨在深刻了解js以及它的工做原理。咱们都知道只有了解更多的js基础才能够写出更好的代码和app。javascript
几乎全部人都听过V8引擎的概念,也知道js是一个单线程活使用回调队列。 在这篇文章中咱们会详细讲解这些概念和解释js工做原理。知道这些你能够利用js提供的api,写出更好的代码,更流畅的app应用。 若是你刚接触js,这篇博文会帮助你理解js和其余语言相比下的不同凡响。 若是你是一个经验丰富的js开发者,在你天天的工做的时候,在js如何运行上给你一些新的体验。前端
谷歌v8引擎是一个js引擎的典型案例。Chrome和node都是用了v8引擎。下面是一个简单的例图: java
- Memory Heap - 内存堆:内存分配
- Call Stack - 调用栈:调用栈框架代码执行
浏览器提供的api几乎被全部js开发者使用(eg:'setTimerout')。然而这些api并非v8引擎提供的。 所以他们来自哪里呢? 事实证实现实是有一点复杂的。node
所以,咱们拥有引擎,但实际上还有更多的东西。有浏览器提供的web api,例如 dom,ajax,setTimeout等等。 并且,咱们还有超级流行的 event loop 和 回调队列。web
js是一个单线程的程序语言,意味着他只有一个调用栈。因此一次只能够作一件事情。 The Call Stack is a data structure which records basically where in the program we are. 若是进入一个函数,咱们把它放入调用栈的顶端。若是我从一个函数返回,咱们把它从调用栈顶端移除,这就是调用栈作的全部事。 看下面demo:ajax
function multiply(x, y) {
return x * y;
}
function printSquare(x) {
var s = multiply(x, x);
console.log(s);
}
printSquare(5);
复制代码
当引擎开始执行代码,调用栈是空的。而后,接下来的步骤如图: 后端
调用栈中的每个表被称为一个 栈框架(Stack Frame) 当异常被抛出的时候,能够清楚的知道堆栈追踪是如何被构成的。异常发生时堆栈的状态。看一下下面的代码:api
function foo() {
throw new Error('SessionStack will help you resolve crashes :)');
}
function bar() {
foo();
}
function start() {
bar();
}
start();
复制代码
若是这发生在 Chrome 里(假设这段代码实在一个名为 foo.js 的文件中),那么将会生成如下的堆栈追踪 浏览器
堆栈溢出(Blowing the stack) - 当你达到调用栈最大的大小的时候就会发生。并且很容易出现,特别是当你在没有彻底的测试你的代码的状况下使用回调。看下面的简单的代码:session
function(){
foo();
}
foo();
复制代码
当引擎开始解析这段代码的时候,就会开始调用foo函数,这个函数是一段从本身开始没有任何终止条件的递归函数。所以在每一步的执行中,一样的函数被一遍一遍放在调用栈中,这看起来就像这样:
当你有函数调用堆栈须要花费大量时间处理的时候,发生了什么?例如,你想要在浏览器中使用js去作一些复杂的图片处理的时候。 你可能会问-这怎么是一个问题?问题是当调用栈有函数要执行。浏览器实际上不能够作别的事情--它被锁住了。这意味着浏览器不能够被渲染,也不能够执行其余的代码,它仅仅是卡住了。并且这会对于你想要完美的ui app中形成问题。 并且不单单是这一个问题。一旦你的浏览器在调用栈中开始执行这么多任务,他可能会在很长时间内中止响应。绝大多数浏览器会采起提出一个错误,询问你是否须要关闭web页面。 如今,这难道不是一个很糟糕的用户体验? 因此,咱们在执行大量代码的时候如何不会阻塞ui和浏览器流畅?就决方案就是 异步回调(asynchronous callbacks)。
会在第二章中有更详细的解释:Inside the V8 engine + 5 tips on how to write optimized code