文章目录
- 1.什么是事件循环
- 2.主线程、任务队列、同步任务、异步任务、微任务、宏任务
- (1)主线程
- (2)同步任务
- (3)异步任务(微任务、宏任务)
- (4)任务队列
- 3.执行流程图
- (1)整体流程图
- (2)含子任务流程图
- 4.面试题
- (1)定时器与promise
- (2)定时器与promise
- (3)定时器与promise
- (4)await后面的任务变成了微任务
1.什么是事件循环
事件循环(Event Loop)是单线程的JavaScript在处理异步事件时进行的一种循环过程,具体来讲,对于异步事件它会先加入到任务队列中挂起,等主线程空闲时会去执行任务队列(Event Queue)中的事件。如此反复循环。事件循环的设计使得 JavaScript 可以在单线程下处理异步操作,避免了阻塞的情况,保证了程序的响应性和流畅性。
简单一句话:
主线程、任务队列、同步任务、异步任务、微任务、宏任务
主线程先执行同步任务,然后才去执行任务队列里的任务,如果在执行宏任务之前有微任务,那么要先执行微任务全部执行完之后等待主线程的调用,调用完之后再去任务队列中查看是否有异步任务,这样一个循环往复的过程就是事件循环!
2.主线程、任务队列、同步任务、异步任务、微任务、宏任务
(1)主线程
JavaScript是单线程的,这意味着JavaScript代码在浏览器中只能按顺序执行,无法同时执行多个任务。这种设计选择主要是出于简化编程模型和避免复杂的多线程同步问题的考虑。尽管JavaScript引擎内部可能包含多个线程,但这些线程主要用于后台处理,如垃圾回收等,而主线程(即执行JavaScript代码的线程)始终保持单线程模式。这种设计使得JavaScript在处理用户交互和页面渲染时能够保持一致的状态,避免了多线程环境中可能出现的竞态条件和同步问题。
JavaScript的单线程特性意味着它在一个时间点只能执行一个任务。当JavaScript代码运行时,如果遇到阻塞操作(如等待用户输入或长时间的计算),则会暂停当前任务的执行,直到该操作完成。这种特性有时会导致页面响应不够流畅,尤其是在执行复杂计算或等待网络请求时。然而,通过使用异步编程技术(如回调函数、Promises或async/await),开发者可以有效地管理这些阻塞操作,提高用户体验。
此外,JavaScript的任务执行模型还包括一个消息队列,用于存放待执行的任务。当主线程空闲时,会从队列中取出任务并执行。这种模型允许JavaScript以非阻塞的方式处理异步事件,如定时器触发、用户交互等,从而实现了在单线程环境中模拟多任务处理的效果
(2)同步任务
同步任务是那些在主线程上排队等待执行的任务,只有前一个任务执行完毕,才能执行后一个任务。
(3)异步任务(微任务、宏任务)
异步任务又分为微任务和宏任务,一般等主线程的听不任务执行完毕后,任务队列中的微任务优先进入主线程执行。
宏任务有哪些
类型 | 有哪些 |
---|---|
宏任务 | 定时器 |
宏任务 | 事件绑定 |
宏任务 | ajax |
宏任务 | 回调函数 |
宏任务 | 定时器Node中fs可以进行异步的I/O操作 |
微任务有哪些
类型 | 有哪些 |
---|---|
微任务 | Promise |
微任务 | process.nextTick |
微任务 | MutationObserver |
(4)任务队列
JavaScript中的任务队列是一种用于存放将要执行的异步任务
3.执行流程图
(1)整体流程图
(2)含子任务流程图
4.面试题
(1)定时器与promise
setTimeout(() => {
console.log(1);
}, 0);
const promise = new Promise((resolve, reject) => {
console.log(2);
resolve()
})
promise.then(() => {
console.log(3);
})
console.log(4);
// 1.先执行同步任务,new Promise的时候会立即执行一次,
// console.log(2);跟console.log(4);同为同步任务,输出2,4
// 2.同步任务执行完,执行异步任务,异步任务分为微任务和宏任务
// promise是为任务先执行,定时器是宏任务后执行。输出3,1
// 3.结果2,4,3,1
(2)定时器与promise
console.log(8);
function workFun(a) {
console.log(6);
if (a) {
console.log(10);
}
return new Promise((resolve, reject) => {
console.log(7);
resolve()
})
}
setTimeout(() => {
console.log(1);
setTimeout(() => {
console.log(3);
}, 0)
workFun('a').then(res => {
console.log(5);
})
}, 0)
workFun().then(res => {
console.log(4);
})
console.log(2)
// 1.先执行同步任务console.log(8);。输出8
// 2.workFun().then,中workFun()是同步任务,执行输出6,7
// 3。console.log(2)是同步任务输出2
// 4.执行异步的微任务workFun().then()。输出4
// 5.执行异步的宏任务。输出1,6,10,7,5,3
(3)定时器与promise
async function method() {
await method2();
console.log(1)
}
function method2() {
const promise = new Promise((resolve) => { setTimeout(() => resolve(), 0) });
return promise;
}
function main() {
method()
console.log(2)
}
main()
// 1.执行main,main中methods是异步函数放入任务队列,输出2
// 2.执行method,method2是异步函数,输出1,
// 结果就是2,1
(4)await后面的任务变成了微任务
console.log("开始");
async function myAwait() {
let a = await fn();
console.log("微队列中1");
console.log('微队列中2');
}
myAwait();
function fn() {
return new Promise((resolve, reject) => {
console.log(123);
resolve()
})
}
console.log("结束");
// 1.输出同步任务,输出,开始、执行myAwait的时候new了一个promise立即执行输出123,在输出结束
// 2.这里为什么没有输出console.log("微队列中1");console.log('微队列中2');这两个是因为在await后面,需要等待外层的任务执行完了,在执行await后面的同步任务宏任务微任务,分别加入宏任务微任务栈