首页 > 基础资料 博客日记
Javascript中的事件循环机制详解
2024-10-15 07:00:06基础资料围观86次
目录
概述
事件循环负责执行代码、收集和处理事件以及执行队列中的子任务。
JavaScript中的事件循环是一种异步执行机制,作用是协调和管理各种异步任务的执行顺序,以确保JavaScript代码执行的顺序和预期一致。
代码在执行时会先执行同步任务,而异步任务则被放入任务队列中等待执行。事件的循环机制会不断地检查任务队列中是否有任务需要执行,如果有,则将任务取出并执行。在执行异步任务时,引擎会挂起当前任务的执行,去执行异步任务,等到异步任务执行完成后,再回到之前的任务继续执行。
事件循环的组成:调用栈、任务队列和事件循环线程。调用栈用来管理代码的执行顺序,任务队列用来存放异步任务,事件循环线程则是一个循环,不断地从任务队列中取出任务执行。
一、进程和线程
在将JavaScript事件循环前先简单了解一下进程和线程
1.进程(Process):
在系统中程序运行需要有它自身的独立内存空间,可以把分配给程序运行的这块内存空间理解为进程。进程是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
每个应用最少需要一个进程,进程与进程之间是独立的存在,即使需要通讯,也需要双方建立关系(同意相互之间通讯)
2.线程(Thread):
线程是系统中能够进行运算的最小单位,一个进程最少有一个线程,所以在进程开启后会主动创建一个线程来运行代码程序,该线程称之为主线程,如果程序代码中需要同时执行多个代码块的话,主线程就会同时开启多个线程来执行,因此一个进程中是可以包含多个线程的。
简单常见的示例,启动浏览器后就会开启多个进程,如浏览器、网络进程、渲染进程等,且浏览器的每一个新的标签页都是独立的进程,而每个进程下都有一个线程,所以说浏览器是一个多进程和多线程的应用。
二、Javascript单线程解释
单线程就意味着,所有任务需要排队,前面的任务结束,才会执行后面的任务。假如一个任务耗时很长,后面的一直等着,就会造成阻塞,不得不等着结果出来,再往下执行。
因为,在设计之初,JavaScript就是单线程,这是Javascript这门语言的核心特征。
为了解决这一问题,Javascript把任务分成两种,一种是同步任务,一种是异步任务。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入任务队列中的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
所以Javascript是单线程代码执行不阻塞主进程一种机制。
Javascript作为浏览器脚本语言,它的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。如果JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器就无法确定以哪个线程为准了。
在HTML5中提出Web Worker标准
Web Worker 是一种浏览器提供的 JavaScript API,它允许在后台线程中运行脚本,而不会阻塞主线程。这意味着,即使脚本执行了很长时间,Web 应用程序的 UI 仍然可以保持响应。
Web Worker 有两种类型:Dedicated Worker 和 Shared Worker。Dedicated Worker 是指与一个页面绑定的 Worker,它仅能由该页面的脚本使用。而 Shared Worker 则可以被多个页面共享使用,这使得多个页面可以同时访问同一个后台线程
即使HTML5中允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。
三、JavaScript事件循环(Event Loop)
Javascript开始执行的时候,会分为两部分进行执行,同步和异步
1、同步任务会直接进入主线程依次执行;
2、异步任务会再分为宏任务和微任务。
当在JavaScript代码执行时,如果遇到一个异步任务,如 setTimeout()、Promise,则会将任务添加到任务队列中,等待执行。在JavaScript引擎空闲时,事件循环线程会不断地从任务队列中取出任务,放入调用栈中执行,直到任务队列为空为止。
当主线程内的任务执行完毕,优先检查微任务的任务队列,如果有任务,就进入主线程进行依次执行,没有就从宏任务队列读取下一个宏任务执行;
每执行完一个宏任务就清空一次微任务队列,不断重复,这就是事件的循环;
来看一个实例
function bobEventLoop(){
console.log("1");
setTimeout(()=>{
console.log("2");
},0);
console.log("3");
}
bobEventLoop();//输出的结果 1、3、2
通过以上代码可以看出,首先执行完了主任务后再执行了异步任务,因为setTimeout是异步任务,所以等主任务执行完了才会执行setTimeout里面的异步任务接下来再使用Promise来创建一个异步任务,看下列实例
function bobEventLoop(){
console.log("1");
setTimeout(()=>{
console.log("2");
},0);
new Promise((resolve, reject)=>{
console.log('3');
setTimeout(() => {
console.log('4');
}, 0);
resolve();
}).then(()=>{
console.log('5')
})
console.log("6");
}
bobEventLoop();//输出的结果 1、3、6、5、2、4
从以上可以new Promise()里面的函数为同步任务
function bobEventLoop(){
console.log("1");
setTimeout(()=>{
console.log("2");
},0);
Promise.resolve().then(()=>{
console.log('3');
setTimeout(() => {
console.log('4');
}, 0);
});
console.log("5");
}
bobEventLoop(); //输出为1、5、3、2、4
因为异步任务可以分为两种,一种是微任务,一种是宏任务,通过以上实例可以看出Promise创建的异步任务优先于setTimeout创建的异步任务,这也说明了微任务的执行是优先于宏任务的执行
列举以下几种(非全部)
宏任务的创建方法有
setTimeout
setInterval
ajax
事件
.....微任务的创建有
new Promise()后的then与catch函数
async
await
总结
当第一个宏任务进入主线程,进行第一次事件循环,如遇到宏任务,则将其分发到宏任务队列中,若遇到微任务,则将其分发到微任务队列中。同步代码执行完毕,微任务队列先进入主线程直至任务执行完毕,下一个宏任务进入主线程开始下一次的事件循环。以上过程会不断重复,直到宏任务队列全部执行完毕,这就是Javascript中的事件循环机制了。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
标签: