JS事件循环机制
1.JS线程
在大众的观念里,js是一个单线程的,但是实际上js有很多线程,但是对外抛出的线程只有一条主线程,除了主线程外,还有事件线程,时间线程,GUI线程,网络线程,不同的线程会对js监听不同的任务,比如,在遇到点击事件时事件线程会监听到相应的事件。
不同的线程任务不同,分工明确,但是这些线程在监听到对应任务时并不会立即执行,因为能执行这些任务的只有主线程,在JS主线程里,会优先执行同步代码,当同步代码执行完毕后才会执行异步代码。
2.执行栈
在JS中能执行任务的线程只有主线程,而执行栈就是JS主线程在执行JS代码是形成的区域,比如,在执行一个函数时,会生成这个函数的执行期上下文,这个执行期上下问中保存着这个函数的作用域,参数,this等,因为JS主线程一个时间只能干一件事,所已,每次只能执行一个函数,在执行函数时会形成一个对应的只执行期上下文,当函数执行完后,又会销毁执行期上下文,以此就形成了入栈执行,出栈销毁的原则,但是有有一类例外,那就是形成了闭包的函数,因为函数的执行期上下文具有继承性,也就是内层函数会继承外层函数的执行期上下文,所以在外层函数执行完后,由于内层函数版保留了外层函数的执行期上下文,所以不会被销毁,这才导致过多使用闭包会造成内存泄露。
3.JS的事件队列
事件队列中的任务都是次要线程监听到代码中有自己负责的区域内的任务时加入的,换句话说,事件队列中的代码都是异步代码,例如:定时器,事件,promise等,也叫异步任务,事件队列和普通的队列数据结构一样,都是先进先出。
4.宏任务(定时器,事件),微任务(promise.then)
在异步任务里,也有不同,比如promise和定时器
setTimeOut(()=>{
console.log(1)
},0)
new Promise((resolve,reject)=>{
resolve(2)
}).then((res)=>{
console.log(res)
})
在上边的代码中,定时器的时间为0,但是执行结果是先打印2后打印1,这就是微任务和宏任务的差别,在事件队列中虽然都是异步任务,但是他们的执行顺序还是不同,在事件队列中分为微任务队列,宏任务队列,当JS执行栈中的任务执行完后,JS主线程会优先检查微任务队列中是否有任务,如果没有才回去检查宏任务队列,所以,在同一次事件循环中,微任务永远在宏任务之前执行。