JS事件的循环
JS运行环境称为宿主环境
ECMAscript 和 JavaScript是什么关系
浏览器端:JavaScript = ECMAscript + WEBAPI
服务器端: Node.js = ECMAscript+ NodeAPI
服务端其实没有JavaScript这个说法,只有ECMAscript这个说法,我们用到的核心语法为ECMAscript,只是我们习惯性把他称为JavaScript,严格上说法JavaScript是跟服务端没有关系的,他的服务端用到的核心语法是ECMAscript。
执行栈()call stack
一个数据结构,存放各种函数的执行环境,每一个函数执行之前,它的相关信息会加入到执行栈中,函数调用之前,会创建执行环境,然后加入到执行栈中,函数调用完成,会销毁执行栈
JS引擎永远执行栈顶。 执行栈的最顶部
下面代码有多少次出栈入栈的操作
所以是七次出栈出栈操作
JS是单线程
异步函数 : 某些函数不会立即执行,需要等到一定的时候才能执行,这种函数称为异步函数,例如事件,定时器
异步函数的执行,会被宿主环境所控制
浏览器执行线程
浏览器有5条线程:
1.js线程(主线程) 负责去执行栈顶的代码
2.GUI线程 (负责渲染页面,解析 HTML,CSS 构成 DOM 树)
js线程和GUI线程会互相等待
3.事件监听线程 负责监听各种事件
4.计时线程 负责定时器
5.网络线程 各种网络请求
当上面的线程发生了某些事情的时候,如果该线程发现,这件事情有处理程序,它会将该程序加入到一个事件队列中,
当JS引擎发现,执行栈没有任何内容,会将事件队列的第一个函数加入到执行栈中执行
执行中的线程:
主线程: 也就是 js 引擎执行的线程,这个线程只有一个,页面渲染、函数处理都在这个主线程上执行。
工作线程: 也称幕后线程,这个线程可能存在于浏览器或js引擎内,与主线程是分开的,处理文件读取、网络请求等异步事件。
任务队列( Event Queue ):
所有的任务可以分为同步任务和异步任务,同步任务,顾名思义,就是立即执行的任务,同步任务一般会直接进入到主线程中执行;而异步任务,就是异步执行的任务,比如ajax网络请求,setTimeout 定时函数等都属于异步任务,异步任务会通过任务队列的机制(先进先出的机制)来进行协调。
同步和异步任务分别进入不同的执行环境,同步的进入主线程,即主执行栈,异步的进入任务队列。主线程内的任务执行完毕为空,会去任务队列读取对应的任务,推入主线程执行。 上述过程的不断重复就是我们说的 Event Loop (事件循环)。
遇到同步任务直接执行,遇到异步任务分类为宏任务(macro-task)和微任务(micro-task)。微任务相当于一个vip,当执行栈清空时,JS引擎首先会将微队列的所有任务依次执行,如果没有微任务,将执行宏任务
宏任务 计时器 事件回调,http回调
微任务 Promise MutationObserver
示例代码
<body>
<ul id="container"></ul>
<button id="btn">点击</button>
<script>
// MutationObserver 监 听dom对象的变化
const ul = document.getElementById("container");
let count = 1;
document.getElementById( "btn" ).onclick = function AAA(){//异步代码
console.log( '添加了一个1i' )
const li = document.createElement("li');
li. innerText = count ++ ;
ul. appendChild(li)
}
const observer = new Mutationobserver(
function BBB(){//异步代码
console.log( 'u1里面内容发生了改变')
})
observer . observe (u1,{
attributes : true ,
childList : true ,
subtree : true
})
//取消监听
observer disconnect();
</script>
把上面代码取消监听注释
上面代码先是添加然后发生改变,这个任务是往微任务中加的
这里我们可以创建一个宏任务setTimeout,然后就是微队列先发生改变,然后宏队列再发生改变