JavaScript事件循环机制EventLoop与函数执行上下文ExcutionContext
07-js事件循环机制EventLoop
队列的数据结构:先进先出,数据从队列的尾部进,从开头出。
小提示: 浏览器端的js和服务端node.js的js事件循环模型不一样
浏览器是多线程的,但是js是单线程的。
浏览器常见的线程:
- JavaScript执行线程:负责执行js代码。
- UI线程:负责UI展示,展示给用户看的页面。
- JavaScript事件循环线程
- JavaScript事件管理线程
注意! JavaScript线程和UI线程是互斥的,也就是说在执行js代码的时候网页会卡主。
原因:js会操作页面上UI元素的变化,UI还在负责展示的时候js改了页面上的东西会造成错乱,所以是互斥的。
为什么js是单线程的?
如果页面上有个按钮,js的一个线程改了这个按钮的样式,另一个线程也改了这个按钮的样式会造成错乱,js为了避免不同数据操作一个同一个元素的同步问题,js是单线程的。
js中的任务(js代码,js语句)有两种,同步任务和异步任务。
- 同步任务执行方式:js的代码交给主线程进行执行,之后任务结束。
- 异步任务执行方式:js任务交给主线程执行之后,执行到某个位置,遇到其他需要配合的东西,它会暂停一下,退出主线程,主线程执行下面的任务。当之前的任务需要的东西准备好了,js主线程会继续执行刚才还没执行完的任务。
同步任务和异步任务包括什么?
- 同步任务:for,求和,js赋值,js运算符,表达式处理…
- 异步任务:dom事件,bom的api处理,ajax
*08-函数执行上下文ExcutionContext
栈:先进后出
栈底压入数据 push( )
栈顶弹出数据 pop( )
EC:函数执行环境(或者函数执行上下文),封装前置需要的东西和后置需要的东西。例如函数的参数,函数的变量等等。。。
ECS:执行环境栈
js程序中函数的嵌套,如函数1调用函数2,函数2又调用函数3,每个函数都会在执行的时候创建执行上下文,如果一个函数执行两次,它会创建两个执行上下文,当然整个js代码也有一个全局上下文。
函数上下文存储在ECS中。js在执行的时候总是在ECS的栈顶拿执行上下文,当前函数执行完成之后,它的执行上下文就从栈顶出栈,并等待垃圾回收。
浏览器的js执行引擎总是访问栈顶的执行上下文,全局上下文只有唯一的一个,它在浏览器关闭时出栈。
- 代码执行之前,立即创建一个全局执行上下文 Golbal Excution Context并放入执行环境栈(ECS)中
- 执行函数f1之前,js执行引擎立即创建一个f1的EC并立即把f1的EC放入ECS中
- 函数f1执行完成之后,从ECS中弹出f1的EC
- 执行函数f2之前,js执行引擎立即创建一个f2的EC并立即把f2的EC放入ECS中
- 因为f2调用了f3所以f3执行之前创建了f3的EC并立即把f3的EC放入ECS中
- 因为f3调用了f4所以f4执行之前创建了f4的EC并立即把f4的EC放入ECS中
- 函数f4执行完成之后,从ECS中弹出f4的EC
- 函数f3执行完成之后,从ECS中弹出f3的EC
- 函数f2执行完成之后,从ECS中弹出f2的EC
- 此时ECS中只有一个golbal EC
09-执行上下文的生命周期
总的的生命周期:创建→执行→出栈等待销毁
相关概念
- VO变量对象(Variable object):是说JS的执行上下文中都有个对象用来存放执行上下文中可被访问但是不能被delete的函数标示符、形参、变量声明等。它们会被挂在这个对象上,对象的属性对应它们的名字对象属性的值对应它们的值但这个对象是规范上或者说是引擎实现上的不可在JS环境中访问到活动对象。
- AO**对象(Activation object):有了变量对象存每个上下文中的东西,但是它什么时候能被访问到呢?就是每进入一个执行上下文时,这个执行上下文儿中的变量对象就被**,也就是该上下文中的函数标示符、形参、变量声明等就可以被访问到了
- scope chain:作用域链
golbal EC中的变量对象叫VO,函数EC中的变量对象叫AO
<script>
var a1 = 19,
a2 = 20,
a3 = 'sss',
b1 = { name: 'laoma'};
a1 = f1(a1, a2);
function f1(a, b) {
var t = 0,
m = 10;
for(var i = 0; i < a; i++) {
console.log(i);
}
function f2() {
console.log(f2);
}
return a + b;
}
</script>
golbal的执行上下文创建
- 因为golbal EC没有参数,所以不会创建argument对象,这一步省略
- 扫描所有的函数声明,找到f1( ) 。
- 扫秒所有变量声明,全部初始化成undefined。 a1=undefined; a2=undefined; a3=undefined; b1=undefined;
- scope chain:作用域链 []
- this {} golobal EC的this就是window
- 之后全局上下文开始执行变量赋值,函数引用以及其他代码。
f1的执行上下文创建
-
扫描参数 a=19;b=20;
-
扫描函数声明f2。 f2=function(){}
-
扫描变量声明 t=undefined; m=undefined; i=undefined
-
scope chain:作用域链 []
-
this
-
开始执行变量赋值,函数引用以及其他代码。
-
f1 EC出栈