当前位置: 首页 > 后端技术 > Node.js

清除执行上下文

时间:2023-04-03 18:04:55 Node.js

清除执行上下文Tag:javascript什么是执行上下文?当JavaScript代码执行一段可执行代码时,相应的上下文(executioncontext)被创建并压入上下文栈(contextstack)。上下文包括以下三个重要属性:名称-变量对象(VO,variableobject)当前函数定义的变量、函数、参数作用域链(Scopechain)源代码定义时形成的作用域链这个上下文是一个抽象概念。为了便于理解,我们假设context是一个对象,包含三个属性:VO、Scope和this:functionfoo(c){leta=1letb=function(){}}//contextoffoofunctionfooContext={VO:{arguments:{//实际参数c:undefind,length:0},a:1,//变量b:对函数的引用(){}//function},Scope:[VO,globalContext.VO],//Scopechainthis:undefind//非严格模式下的this}所以上下文就是函数运行时的环境或者依赖资源的集合,决定了函数运行时可以获取到哪些变量和函数跑步。执行上下文(EC):如果函数正在执行,则函数的上下文称为执行上下文,如果函数未执行,则称为(普通)上下文。所以执行上下文只是上下文的不同状态,本质上它们没有区别。上下文堆栈上下文堆栈也称为执行堆栈(ECS)。浏览器中的javascript解析器本身是单线程的,即一次只能处理一个上下文和对应的代码段,所以javascript解析引擎使用上下文栈来管理上下文。所有上下文创建后都会保存在上下文栈队列中。栈底是全局上下文,栈顶是当前正在执行的上下文。一个context就是一个执行单元,javascript以栈的方式管理执行单元。页面初始化时,会先将全局上下文压入栈底,然后在可执行函数按规则执行时将函数上下文压入上下文栈。pushedcontext包含了函数运行所需要的资源(Variableobject,scopechain,this),这些资源提供给函数运行时的表达式使用。执行上下文可以理解为函数运行的环境。同时,执行上下文也是一个看不见的概念。javascript中有3种运行环境:全局环境:浏览器中的window,node环境中的global,页面初始化时,全局上下文会被压入上下文栈;函数环境:当函数被调用执行时,会收集Function资源,创建上下文并压入上下文栈;eval环境,弃用运行时环境将对应一个上下文。栈顶的上下文执行完后,会自动出栈,依次往下,直到所有上下文运行完毕,最后在浏览器关闭时销毁全局上下文。举个例子方便大家理解:leti=0functionfoo(){i++console.log(i,'foo')}functiontoo(){i++console.log(i,'too')foo()}functiondon(){i++console.log(i,'don')too()}don()//1"don"//2"too"//3"foo"上面代码的逻辑就是执行首先是don(),然后是too()、foo()。foo()执行时的上下文栈如下:我们假设上下文栈是一个数组:ECStack:ECStack=[]javascript加载后首先解析执行的是全局代码,所以会全局上下文初始化时压入上下文栈,我们用globalContext来表示。ECStack=[globalContext]全局作用域在整个代码运行阶段一直存在,直到页面关闭,清空ECStack,销毁globalContext。当创建全局上下文时,会进行变量提升、变量对象生成等操作,然后执行当前上下文中的可执行代码(函数、表达式)。当遇到函数调用时,函数的上下文会被压入上下文栈。functionfoo(){console.log('foo')}functiontoo(){console.log('too')foo()}functiondon(){too()}don()执行逻辑可以理解为:execute到don(),分析don函数内部代码,生成don函数的上下文(vo,Scopechain,this)将don的上下文推送到ECStack,执行don函数体内的表达式Executetoo()生成too函数的上下文(vo,Scopechain,this)Scopechain,this)将too的上下文推入ECStack...javascript解析器不断递归,直到执行foo函数...foo函数上下文是popped...然后又回到globalContext上下文...等等...当事件回调函数被激活后,执行回调函数。(这里涉及到javascript的执行机制和事件循环,请关注后续文章^_^)执行逻辑伪代码如下://伪代码//don()ECStack.push(functionContext);//在don调用too中,将too的上下文压入上下文栈ECStack.push(functionContext);//在too中调用foo,将foo的上下文压入上下文栈ECStack.推送(函数上下文);//foo执行,弹出上下文ECStack.pop();//too执行,弹出上下文ECStack.pop();//don执行,弹出上下文ECStack.pop();//非全局上下文执行弹出后,会一直停留在全局上下文中,直到页面关闭。需要注意的是,上下文和范围是不同的概念。上下文是一个运行时概念。浏览器运行后,执行js代码,将不同的上下文添加到上下文栈中,并在顶层上下文对应的代码块执行完后销毁上下文。作用域是一个静态的概念,是根据代码片段的位置和词法关系建立的。无论浏览器是否运行,源代码的范围关系和变量的访问权限都保持不变。