Javascript是一门单线程语言,这意味着只有一个调用栈,因此同一时间只能做一件事。
·同步和异步任务分别进入不同的执行“场所”,同步的进入主线程,形成一个执行栈;
· 主线程之外,还存在一个“任务队列”(task queue),只要异步任务有了运行结果,就在“任务队列”之中放置一个事件;
·一旦“执行栈”中的所有同步任务执行完毕,系统就会读取“任务队列”,看看里面有哪些事件。那些对应的异步于是结束等待状态,进入执行栈,开始执行;
·主线程会不断重复上面三步,主线程从“任务队列”中读取事件,这个过程循环不断,所以整个运行机制也叫Event Loop(事件循环)。
同步任务只有在前一个任务执行完毕才能执行后一个任务,异步任务指的是只有等主线程执行完毕,“任务队列”开始通知主线程,请求任务才会进入主线程执行。
同步:上一件事情做完了才能继续下一步。
异步:规划要做一件事,等一定时间才能继续执行。(setTimeOut)

调用栈
调用栈是一种解释器(就像浏览器中的javascript解释器)追踪函数执行流的一种机制。当执行环境中调用了多个函数时,通过这种机制,我们能够追踪到哪个函数正在执行,执行的函数体中又调用了哪个函数。
·每调用一个函数,解释器就会把该函数添加进调用栈并开始执行;
·正在调用栈中执行的函数还调用了其他函数,那么新函数也将会被添加进调用栈,一旦这个函数被调用,便会立即执行。
·当前函数执行完毕后,解释器将其清出调用栈,继续执行当前执行环境中的剩余代码;
·当分配的调用栈空间被占满时,会引发“堆栈溢出”。
调用栈是一种拥有LIFO(后进先出)数据结构的栈,被用来储存代码运行时创建的所有执行上下文。
当Javascript引擎第一次遇到你的脚本时,会创建一个全局的执行上下文并且压入当前执行栈。如果我们运行到一个函数,他将会将其放置到栈顶,当这个函数返回的时候,就会将这个函数从栈顶弹出,这就是调用栈做的事情。
function multiply(x,y) {
return x*y;
}
function printSquare(x) {
var s = multiply(x,x);
console.log(s)
}
printSquare(3);
javaScript中的执行上下文和执行栈
JavaScript有三种执行上下文类型:
·全局执行上下文——这是默认或者说是基础的上下文,任何不在函数内部的代码都在全局上下文中。它会执行两件事:创建全局的window对象(浏览器的情况下),并且设置this的值等于这个全局对象。一个程序中只会有一个全局执行上下文;
·函数执行上下文——每当一个函数被调用时,都会为该函数创建一个新的上下文。每个函数都有它自己的执行上下文,不过实在函数被调用时创建的,。函数上下文可以有任意多个,每当一个新的执行上下文被创建,它会按定义的顺序执行一系列步骤;
·Eval函数执行上下文——执行在eval函数内部的代码也会有属于他自己的执行上下文,但JavaScript开发者并不经常使用eval.
如何创建执行上下文
创建执行上下文有两个阶段:创建阶段、执行阶段
- 创建阶段:
- this值的决定(即this绑定);
- 创建词法环境组件
- 创建变量环境组件
ExecutionContext = {
ThisBinding = <this value>,
LexicalEnvironment = {...},
VariableEnvironment = {...}
}- this绑定
this的值指向全局对象(在浏览器中,this引用window对象,nodejs中指向这个文件的module对象)函数执行上下文中,this的值取决于该函数是如何被调用的,如果它被一个用用对象调用,那么this会被设置成那个对象,否则this的值被设置为全局对象或者undefined(严格模式下)。