一 事件轮询的含义和原理
JavaScript 事件轮询(event loop)是 JavaScript 运行时环境中的一个机制,它允许 JavaScript 能够执行非阻塞的异步操作。这是因为 JavaScript 在大多数环境下(比如 Web 浏览器、Node.js)中是单线程运行的,意味着在任何给定的时刻它只能执行一个任务。事件轮询使得 JavaScript 能够表现出异步行为,即使它在内部是单线程的。
事件轮询的工作原理大致如下:
1.调用栈(Call Stack) : 当代码开始执行时,它首先在调用栈中处理。如果一个函数被执行,它就被添加到调用栈中,当函数执行完成后,它就会被移除。
2.事件队列(Event Queue) : 当 JavaScript 运行时环境得到一些不在当前执行堆栈中的事件(例如,用户输入、定时器计时器完成、异步操作完成等)时,这些事件就会被放置到事件队列中。
3.事件循环(Event Loop) : 当调用栈清空,即没有更多代码执行时,事件循环就会检查事件队列。如果队列中存在事件,那么事件循环就会依次取出一个事件,并将相关的回调函数放到调用栈中,这样回调函数就可以执行了。
4.Web APIs/Web Platform APIs: 浏览器提供的一些异步API(如 setTimeout, XMLHttpRequest)并不直接由 JavaScript 引擎管理,它们可以被看作是环境级的 Web APIs。当这些 API 操作完成时(如定时器到期),它们会将回调函数放到事件队列中,等待事件循环后续的处理。
二 简单事件轮询解析
console.log('A'); // 第一个
setTimeout(() => {
console.log('B'); // 第七个
}, 0);
new Promise(resolve=>{
console.log('C'); // 第二个
resolve()
}).then(()=>{
console.log('D'); // 第五个
})
setTimeout(() => {
console.log('E'); // 第八个
new Promise(resolve=>{
console.log('F'); // 第九个
setTimeout(() => {
console.log('G'); // 第十二个
});
resolve()
}).then(()=>{
console.log('H'); // 第十个
})
}, 0);
new Promise(resolve=>{
console.log('I'); // 第三个
resolve()
}).then(()=>{
console.log('J'); // 第六个
setTimeout(() => {
console.log('K'); // 第十一个
});
})
console.log('L'); // 第四个
首先事件轮询中 分为 同步任务 异步任务 ,异步任务又分为异步微任务和异步宏任务,同步任务首先进行执行,同步任务执行完,异步微任务进行执行,最后是异步宏任务进行执行,所以只要分清楚什么是同步、什么是异步,这些题就很好做了。
console.log()
new Promise(()=>{
})
是同步任务
Promise 的回调任异步微任务
延时器(setTimeout) 和 定时器(setInterval)是异步宏任务
所以 A C I L是同步任务 安顺序进行执行 后面是 D J 是异步微任务 随后执行 最后是异步宏任务延时器(setTimeout) 中包含的同步任务和异步任务 继续安顺序执行 B E F H K G
同优先级任务 遵循先进先出原则
三 async和await是 ECMAScript 2017 引入的特性,用于处理异步操作的语法糖。它们可以让异步代码以同步的方式编写,使代码更加清晰和易于理解。
async function async1(){
console.log('A'); //2
await async2()
console.log('B');//6
}
async function async2(){
console.log('C'); //3
}
console.log('D'); //1
setTimeout(function() {
console.log('E');//8
}, 0);
async1()
new Promise(function(resolve){
console.log('F');//4
resolve()
}).then(function(){
console.log('G'); //7
})
console.log('H');//5
输出结果为 D A C F H B G E
其中await 可以简单理解为Promise的封装
async function foo() {
console.log(1);
await bar();
console.log(2);
}
async function bar() {
console.log(3);
}
foo();
console.log(4); //1342
上面这段代码可以简单解析为
function foo(){
console.log(1);
new Promise(resolve=>{
bar()
resolve()
}).then(()=>{
console.log(2);
})
}
function bar(){
console.log(3);
}
foo()
console.log(4);
四 那些任务是异步微任务 那些任务是异步宏任务
异步微任务
Promise的then、catch和finally方法会创建微任务。MutationObserver的回调函数也会创建微任务。- 通过
queueMicrotask函数添加的任务也是微任务。
异步宏任务
setTimeout和setInterval函数会创建宏任务。- 用户交互事件(如点击、键盘事件等)也是宏任务。
requestAnimationFrame方法也创建一个宏任务。
JavaScript引擎内部的方法都是异步微任务
浏览器方法是异步宏任务