浅析javascript调用栈

你们在进行javascript开发的时候,有没有想过,咱们写的代码是怎么样运行的呢?下面咱们就来剖析一下代码的执行过程。javascript

一 什么是调用栈

代码在运行过程当中,会有一个叫作调用栈(call stack)的概念。调用栈是一种栈结构,它用来存储计算机程序执行时候其活跃子程序的信息。(好比什么函数正在执行,什么函数正在被这个函数调用等等信息)。调用栈是解析器的一种机制。call stackhtml

咱们以一段简单代码为示例,来看一看到底什么是调用栈,它是一个怎么样的运行机制java

function boo (a) {
    return a * 3
  }
  function foo (b) {
    return boo(4) * 2
  }
  console.log(foo(3))

二 详解代码执行

下面咱们来分析一下上述代码的执行过程
(1)console.log(foo(3)) 执行,造成一个栈帧,调用foo函数,再造成另外一个栈帧。
(2)新的栈帧压在上一个栈帧之上,继续执行代码,foo函数中又调用了boo函数,造成了另外一个栈帧压在旧栈帧之上。而后执行boo。
(3)当执行完boo时候,返回值给foo函数以后,boo被推出调用栈,foo函数继续执行,而后foo函数执行完,返回值给console.log,foo函数被推出调用栈,console.log获得foo函数的返回值,运行,输出结果,最后console.log也被推出调用栈,该段程序执行完成。
图解代码运行过程:
图片描述数据结构

三 一个更复杂的例子

// 省略一部分html
<button>click</button>
$.on('button', 'click', function onClick() {
    setTimeout(function timer() {
        console.log('You clicked the button!');    
    }, 0);
});

console.log("Hi!");

setTimeout(function timeout() {
    console.log("Click the button!");
}, 5000);

console.log("My Name Is Chirs.")

你们看看上叙的代码,结合一下前面的的分析,思考一下调用栈是怎么工做的?
(1)先运行绑定事件函数,把onClick事件绑定在button标签上。该函数没有没有调用其余函数。
(2)接下来运行console.log("hi"),该函数没有调用任何其余函数。
(3)而后继续执行下面的setTimeout,setTimeout是一个异步函数,通过5秒以后,在运行队列里面插入这个回调函数,而后若是该队列以前没有其余函数,就执行该队列,有则等待前面的函数执行完成,再执行。
(4)console.log("My Name Is Chirs")不会等待5s以后,再执行,由于settimeout并不会在调用栈中执行5秒,实际上它在调用栈中是当即执行完的。
(5)假设在这个时候,咱们点击了按钮,按钮绑定的回调事件被添加到运行队列中。(运行队列中的代码要等调用栈被清空以后才会执行)因为调用栈中还有代码须要执行,因此会继续执行下面的console.log()
(6)而后执行完console.log以后,因为时间尚未通过5s,因此点击的回调事件会被先压入栈中去执行,因为该回调事件里面又是一个settimeout事件,因为它的事件间隔只有0s,因此这个settimeout的回调会先被压入运行队列。先输出You clicked the button! 再过几秒以后,间隔为5s的settimeout把回调函数压入队列,这时候调用栈中没有代码在执行,因此会执行这个代码,输出"Click the button“。结束代码运行。异步

一样来看一个运行示意图:
process3函数

四 总结

调用栈其实就是一种解析器去处理程序的机制,它是栈数据结构。它能追踪子程序的运行状态。
(1)当脚本要调用一个函数时,解析器把该函数添加到栈中而且执行这个函数。并造成一个栈帧
(2)任何被这个函数调用的函数会进一步添加到调用栈中,造成另外一个栈帧,而且运行到它们被上个程序调用的位置。
(3)当执行完这个函数后,若是它没有调用其余函数,则它会从调用栈中推出。而后调用栈继续运行其余部门。
(4) 异步函数的回调函数通常都会被添加到运行队列里面,如settimeout会在响应的时间后把回调函数放入队列中,队列里的函数须要等栈为空时才会被推入栈中执行。若是队列中有其余函数,须要等队列前面的函数被堆入调用栈中以后才会运行。spa

相关文章
相关标签/搜索