【温故而知新】JavaScript事件循环
一、概念
JavaScript事件循环是一种机制,用于处理由于用户交互、异步操作或计时器等事件引起的回调函数。
JavaScript是一种单线程语言,意味着只能执行一个任务。事件循环通过维护一个事件队列来处理事件回调函数。当一个事件被触发时,相关的回调函数被推入事件队列中,并在适当的时候被执行。
事件循环由以下几个主要组件组成:
-
事件队列(Event Queue):用于存储待处理的事件回调函数。事件队列是一个先进先出(FIFO)的数据结构。
-
执行栈(Execution Stack):用于存储当前正在执行的代码。
-
主线程(Main Thread):负责执行JavaScript代码,并处理事件。
事件循环的工作流程如下:
-
JavaScript代码开始执行。
-
遇到异步任务(如定时器、AJAX请求等),将其添加到事件队列中。
-
执行栈为空时,事件循环从事件队列中取出第一个待处理的回调函数,并将其推入执行栈中。
-
执行栈开始执行回调函数的代码。
-
如果回调函数中包含了异步任务,将其添加到事件队列中。
-
执行栈为空时,重复步骤3-5。
通过事件循环,JavaScript能够以非阻塞方式处理异步任务,保证用户界面的响应性,并在需要时执行相应的回调函数。
二、案例
- 一个简单的JavaScript事件循环的案例代码:
console.log("Start");
setTimeout(function() {
console.log("Timeout 1");
}, 2000);
setTimeout(function() {
console.log("Timeout 2");
}, 1000);
console.log("End");
在这个例子中,我们使用setTimeout
函数来模拟异步任务。setTimeout
函数会在指定的时间延迟后将回调函数添加到事件队列中。在该代码中,我们使用两个setTimeout
函数,一个延迟时间为2秒,另一个延迟时间为1秒。
首先,我们会输出"Start",然后立即输出"End"。这是因为在执行这两行代码时,setTimeout
的回调函数还没有被执行,而是被添加到了事件队列中。
然后,事件循环会开始处理事件队列。在2秒后,事件队列中的第一个回调函数将被执行,输出"Timeout 1"。在另一个1秒后,事件队列中的第二个回调函数将被执行,输出"Timeout 2"。
因此,最终的输出顺序将是:
Start
End
Timeout 2
Timeout 1
这个例子展示了事件循环的基本工作原理,即在执行栈为空时,事件循环会从事件队列中取出待处理的回调函数并执行。
- 宏任务(macrotask)和微任务(microtask)
在JavaScript中,事件循环中的任务分为两类:宏任务(macrotask)和微任务(microtask)。它们的执行顺序有所不同。
宏任务是由浏览器提供的任务源,包括但不限于以下几种:
- setTimeout
- setInterval
- I/O 操作
- 页面渲染
而微任务是由JavaScript自身提供的任务源,包括但不限于以下几种:
- Promise
- MutationObserver
- process.nextTick(在Node.js中)
在事件循环中,当执行栈为空时,事件循环会从宏任务队列中取出一个任务执行,当这个宏任务执行完毕后,会在执行下一个宏任务之前,检查并执行微任务队列中的任务。
举个例子,考虑以下代码:
console.log('Start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {
console.log('Promise');
});
console.log('End');
执行顺序如下:
- 输出"Start"。
- 将
setTimeout
函数的回调函数添加到宏任务队列中。 - 将
Promise
的.then
回调函数添加到微任务队列中。 - 输出"End"。
- 此时,执行栈为空,事件循环会检查微任务队列,执行微任务中的函数,输出"Promise"。
- 最后,事件循环会执行宏任务队列中的任务,输出"setTimeout"。
因此,最终的输出顺序为:
Start
End
Promise
setTimeout
宏任务会在事件循环的不同阶段执行,而微任务会在每个宏任务执行完毕后立即执行。这种执行顺序可以用来处理优先级较高的任务,并避免阻塞UI渲染。
- async/await
async/await 是 ECMAScript 2017 中引入的一种异步编程的语法糖,它基于 Promise 实现,使得异步代码的编写更加简洁和易读。
async/await 是通过将异步操作包装在一个 Promise 中,然后使用 await 关键字来等待该 Promise 的解析结果。使用 async 关键字标记一个函数,这个函数将会返回一个 Promise 对象。
在一个使用 async 关键字标记的函数中,可以使用 await 关键字来等待一个返回 Promise 对象的表达式。await 关键字会暂停函数的执行,直到 Promise 对象被解析或拒绝。
以下是一个使用 async/await 的简单示例:
function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function fetchData() {
console.log('Fetching data...');
await delay(2000); // 等待2秒钟
console.log('Data fetched!');
}
fetchData();
在上面的示例中,fetchData
函数是一个使用 async 关键字标记的异步函数。在函数内部,我们使用 await 关键字等待 delay
函数返回的 Promise 对象被解析,然后继续执行后续的代码。
在这个例子中,首先会打印 “Fetching data…”,然后等待2秒钟,最后打印 “Data fetched!”。
async/await 的优势在于它让异步代码的书写和理解更加直观和简单,避免了回调地狱和过多的嵌套。
需要注意的是,async/await 只能在支持 Promise 的环境中使用,如果要在老版本的浏览器中使用,可以通过使用 Babel 等工具进行转换。
三、后记
JavaScript是一种广泛应用于网页开发的脚本语言,它可以用来为网页添加交互性和动态特效。JavaScript可以在网页中直接嵌入,也可以作为外部文件引用。
以下是JavaScript的一些重要特点和用法:
- 脚本语言:JavaScript是一种解释型脚本语言,不需要编译,可以直接在浏览器中执行。
- 弱类型语言:JavaScript是一种弱类型语言,变量的数据类型可以随时改变,不需要声明变量的类型。
- 事件驱动:JavaScript可以通过监听用户的操作或者其他事件触发特定的代码执行,实现网页的交互性。
- DOM操作:JavaScript可以通过文档对象模型(DOM)来操作网页的HTML元素,可以动态地添加、修改和删除元素。
- 表单验证:JavaScript可以通过表单验证来确保用户输入的数据符合要求,提供更好的用户体验。
- AJAX:JavaScript可以通过AJAX技术实现网页的异步加载,可以在不刷新整个页面的情况下更新部分内容。
- JSON:JavaScript Object Notation(JSON)是一种轻量级的数据交换格式,JavaScript可以很方便地解析和生成JSON数据。
- 库和框架:JavaScript拥有丰富的库和框架,如jQuery、React、Angular等,可以简化开发过程并提供更强大的功能。
JavaScript是一种强大且灵活的语言,可以用来创建复杂的交互式网页,并且可以与HTML和CSS无缝配合,实现出色的用户体验。
四、热门文章
【温故而知新】JavaScript的Document对象
【温故而知新】JavaScript的BOM之Screen/Location/History对象
【温故而知新】JavaScript的BOM之Navigator对象
【温故而知新】JavaScript的BOM之Window对象
【温故而知新】JavaScript数据结构详解
【温故而知新】JavaScript数据类型
RESTful API,如何构建 web 应用程序
jQuery实现轮播图代码
vue实现文本上下循环滚动
Vue运用之input本地上传文件,实现传参file:(binary)
js判断各种浏览器
uni-app详解、开发步骤、案例代码
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!