写给Pythoner的前端进阶指南(五):事件驱动模型

JavaScript 是一种高度事件驱动的编程语言,尤其在浏览器端的开发中,几乎所有的交互和操作都是基于事件的。在 JavaScript 中,事件驱动模型是处理异步任务和用户交互的核心机制。通过事件驱动模型,程序可以在事件发生时做出响应,而不需要阻塞其他操作。理解事件循环、事件绑定和事件代理的机制,将有助于你编写高效、响应迅速的代码。

如果你熟悉 Python 中的事件驱动框架(如 asyncio 或 Twisted),你将会发现 JavaScript 中的事件驱动模型与这些框架在概念上有些相似,但在实现方式上有所不同。本篇文章将帮助你理解 JavaScript 的事件驱动模型,并与 Python 的事件驱动模型进行对比。

一、事件循环

1.1 事件循环机制

在 JavaScript 中,事件循环(Event Loop)是处理异步任务的核心。JavaScript 是单线程的,这意味着它一次只能执行一个任务。但通过事件循环机制,JavaScript 可以非阻塞地执行异步操作(如 I/O 操作、定时器等),并在任务完成后继续处理其他任务。

事件循环的工作原理可以分为以下几个步骤:

  1. 调用栈:执行同步任务的地方。当执行一个函数时,它会被推入调用栈,执行完成后弹出。
  2. 事件队列:当异步任务(如定时器、网络请求等)完成时,它们的回调会被放入事件队列中等待执行。
  3. 事件循环:事件循环会不断检查调用栈是否为空。如果调用栈为空,事件循环就会从事件队列中取出第一个回调函数,并将其推入调用栈执行。

这个机制允许 JavaScript 在执行异步操作时不会阻塞主线程,从而实现高效的并发处理。

事件循环的例子:
console.log("Start");setTimeout(() => {console.log("Asynchronous Task 1");
}, 0);setTimeout(() => {console.log("Asynchronous Task 2");
}, 0);console.log("End");// 输出顺序:
// Start
// End
// Asynchronous Task 1
// Asynchronous Task 2

尽管 setTimeout 的延迟时间是 0,但它的回调函数仍然会被推迟到主线程空闲时执行,因为它们是异步任务,等待调用栈清空后才会被执行。

1.2 事件循环与异步任务的关系

JavaScript 的事件循环使得异步操作(如定时器、网络请求等)可以在后台进行处理,而主线程则继续执行其他任务。回调函数在异步任务完成后被放入事件队列,等待主线程执行。

这种机制使得 JavaScript 在处理多个并发任务时非常高效,但由于其单线程的特点,也需要开发者特别注意避免长时间的同步任务阻塞事件循环。

二、事件绑定

2.1 使用 addEventListener 绑定事件

在 JavaScript 中,事件绑定是指将事件监听器附加到 DOM 元素上,以便在用户触发事件时执行相应的回调函数。常用的事件方法是 addEventListener,它允许我们绑定各种类型的事件(如点击、键盘输入、鼠标移动等)。

使用 addEventListener 绑定事件的示例:
// 绑定点击事件
const button = document.querySelector('button');
button.addEventListener('click', function() {console.log('Button clicked!');
});

通过 addEventListener,你可以为 DOM 元素绑定多个事件监听器,而且每个事件监听器都可以被移除。与旧的 onclick 事件处理方式相比,addEventListener 更加灵活和强大。

2.2 事件对象

当事件被触发时,事件对象(event)会被自动传递给事件处理函数。这个对象包含了与事件相关的各种信息,如触发事件的元素、事件类型、鼠标位置等。

事件对象的使用示例:
document.addEventListener('click', function(event) {console.log(`Event type: ${event.type}`);console.log(`Mouse position: (${event.clientX}, ${event.clientY})`);
});

2.3 移除事件监听器

你可以使用 removeEventListener 方法来移除已绑定的事件监听器。需要注意的是,只有通过 addEventListener 添加的事件监听器才能被移除,而直接在元素属性上定义的事件(如 onclick)无法移除。

移除事件监听器的示例:
function handleClick() {console.log('Button clicked!');
}const button = document.querySelector('button');
button.addEventListener('click', handleClick);// 移除事件监听器
button.removeEventListener('click', handleClick);

三、事件代理

3.1 事件代理的概念

事件代理是通过将事件监听器绑定到父元素(或更高层次的元素),而不是每个子元素,来提高性能的一种技术。这样,事件处理程序不会被绑定到每个子元素上,而是通过冒泡机制捕获子元素的事件。

事件代理的核心思想是利用事件的冒泡机制:当子元素触发事件时,事件会从子元素冒泡到父元素,你可以在父元素上监听这个事件,然后根据目标元素来处理不同的事件。

事件代理的示例:
const parentDiv = document.querySelector('#parent');parentDiv.addEventListener('click', function(event) {if (event.target && event.target.matches('button')) {console.log('Button clicked:', event.target);}
});

在这个例子中,我们将事件监听器绑定到父元素 #parent 上,而不是每个 button 元素。只有当点击的目标是 button 元素时,回调函数才会被执行。这样做的好处是减少了 DOM 元素上的事件绑定,提高了性能,尤其是在处理大量动态生成的子元素时。

3.2 事件代理的优势

  1. 减少内存占用:避免为每个子元素单独绑定事件监听器,节省了内存。
  2. 动态添加元素支持:如果你动态添加了新的子元素,事件代理依然能正常工作,因为事件监听器绑定在父元素上。
  3. 提高性能:通过减少事件绑定的数量,减少了 DOM 操作,从而提高了页面性能。

四、与 Python 的事件模型对比

4.1 Python 的事件驱动框架

Python 也有一些事件驱动框架,用于处理异步事件和 I/O 操作。最著名的一个框架是 asyncio,它是 Python 3.3 引入的标准库,提供了协程、事件循环、异步 I/O 等功能。

此外,Python 中的 Twisted 框架也是一个基于事件驱动的网络编程框架,广泛用于构建高性能的网络应用。与 JavaScript 的事件驱动模型不同,Python 的事件驱动框架通常用于处理高并发的 I/O 操作,并支持通过协程和异步任务来管理事件。

4.2 事件模型的异同

  • 事件循环:JavaScript 的事件循环模型与 Python 中 asyncio 的事件循环模型类似,都是基于事件驱动的异步编程方式。JavaScript 通过事件循环来处理异步任务,而 Python 则通过 asyncio 的事件循环来调度协程任务。
  • 事件处理:在 JavaScript 中,事件通过事件绑定和事件代理来处理 DOM 事件,而在 Python 中,事件驱动框架(如 Twisted)主要用于处理网络事件或 I/O 操作。
  • 语法和使用方式:JavaScript 的事件驱动模型通过事件监听器和回调函数来实现,而 Python 的事件驱动框架则通过协程和事件循环来实现异步编程。

4.3 Python 的异步 I/O 示例(asyncio

import asyncioasync def fetch_data():await asyncio.sleep(1)print("Data fetched")async def main():await fetch_data()# 运行异步任务
asyncio.run(main())

尽管语法不同,但两者的核心概念都是通过事件循环来管理和调度异步任务。

结语

JavaScript 的事件驱动模型是前端开发的基石,理解事件循环、事件绑定和事件代理的工作原理将帮助你更好地处理异步任务和用户交互。与 Python 中的事件驱动框架相比,JavaScript 的事件驱动模型更侧重于 DOM 事件和浏览器中的用户交互,而 Python 的事件驱动框架更多地应用于高性能的网络编程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/494716.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络管理 详细讲解

讲一下之前获取CPU的,其余的原理和这个一样 python代码 app.route(/cpu/) def cpu_used():cpuoidObjectType(ObjectIdentity(myOIDs[cpu_loads]))ret getTableRows((cpuoid,))cpuload0for i in ret:cpuload i[0]print(cpuload)return {cpu:cpuload} var dom do…

用Python PySide6 复刻了两软件UI 做下练习

图样 1 代码 1: # -*- coding: utf-8 -*-import sys from PySide6.QtCore import (QCoreApplication, QMetaObject, QRect, QDate) from PySide6.QtGui import QIcon, QPixmap, QColor from PySide6.QtWidgets import (QApplication, QDialog, QLineEdit, QPushBut…

【day14】异常处理与Object类深入解析

【day13】回顾 在深入探讨异常处理与Object类之前,让我们回顾一下【day13】中的关键内容: 权限修饰符: public:最广的访问范围,任何地方都可以访问。protected:在同包和子类中可以访问。默认(无…

题解 洛谷 Luogu P1135 奇怪的电梯 广度优先搜索 BFS C/C++

题目传送门: P1135 奇怪的电梯 - 洛谷 | 计算机科学教育新生态https://www.luogu.com.cn/problem/P1135思路: 一道比较裸的 BFS,就是把走迷宫每次搜周围相邻四格,改成了楼层每次搜上下方向的某层而已 感觉这个题难度只有普及- …

苏黎世联邦理工学院与加州大学伯克利分校推出MaxInfoRL:平衡内在与外在探索的全新强化学习框架

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…

第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ

Q1、统计符合条件长度为3的子数组数目 1、题目描述 给你一个整数数组 nums ,请你返回长度为 3 的子数组,满足第一个数和第三个数的和恰好为第二个数的一半。 子数组 指的是一个数组中连续 非空 的元素序列。 2、解题思路 我们需要在给定的数组 nums…

【RAG实战】Prompting vs. RAG vs. Finetuning: 如何选择LLM应用选择最佳方案

在构建基于大型语言模型(LLM)的应用时,通常不可能立即使用模型而无需任何调整。为了保持高实用性,我们可以选择以下几种方法之一: Prompt Engineering(提示工程)Fine-tuning(微调&a…

Odoo:免费开源ERP的AI技术赋能出海企业电子商务应用介绍

概述 伴随电子商务的持续演进,客户对于便利性、速度以及个性化服务的期许急剧攀升。企业务必要探寻创新之途径,以强化自身运营,并优化购物体验。达成此目标的最为行之有效的方式之一,便是将 AI 呼叫助手融入您的电子商务平台。我们…

如何打造用户友好的维护页面:6个创意提升WordPress网站体验

在网站运营中,无论是个人博主还是大型企业网站的管理员,难免会遇到需要维护的情况。无论是服务器迁移、插件更新,还是突发的技术故障,都可能导致网站短暂无法访问。这时,设计维护页面能很好的缓解用户的不满&#xff0…

定位方式:css

使用相对路径 div ul #div下的所有ul,空格表示相对路径(这个实际中用的多一些) 绝对路径-一般不用绝对路径 html>head>div,“>”表示根路径 使用class名称定位 使用.表示 使用id定位 使用#表示 使用属性定位 [属性名…

【YashanDB知识库】jdbc查询st_geometry类型的数据时抛出YAS-00101错误

本文内容来自YashanDB官网,原文内容请见 https://www.yashandb.com/newsinfo/7802956.html?templateId1718516 问题现象 某客户的业务在通过YashanDB jdbc驱动查询含有st_geometry列的数据时,报如下异常:YAS-00101 cannot allocate 0 byte…

[Unity]Unity集成NuGet-连接mysql时的发现

本次使用软件信息: Unity:2022.3.34f1c1。 mysql:mysql 8.0 安装于远程服务器。 使用插件:NuGetForUnity4.1.1.unitypackage 点击名称可前往下载界面。 一、导入插件 打开Unity的时候可直接双击导入道assets。导入后如下图&…

重温设计模式--外观模式

文章目录 外观模式(Facade Pattern)概述定义 外观模式UML图作用 外观模式的结构C 代码示例1C代码示例2总结 外观模式(Facade Pattern)概述 定义 外观模式是一种结构型设计模式,它为子系统中的一组接口提供了一个统一…

HDR视频技术之十一:HEVCH.265 的 HDR 编码方案

前文我们对 HEVC 的 HDR 编码优化技术做了介绍,侧重编码性能的提升。 本章主要阐述 HEVC 中 HDR/WCG 相关的整体编码方案, 包括不同应用场景下的 HEVC 扩展编码技术。 1 背景 HDR 信号一般意味着使用更多比特,一般的 HDR 信号倾向于使用 10…

shardingsphere分库分表项目实践1-让shardingsphere运行起来

学习新技术最快的方式就是: 1. 先找一个比较完善的demo跑起来 2. 弄清楚用法:配置、原理、使用场景 3. 移植到自己项目上,按照自己需求进行修改优化。 找demo项目的方法:优先去官方git库找,如果没有或者过于简单那么…

【QSS样式表 - ⑥】:QPushButton控件样式

文章目录 QPushBUtton控件样式QSS示例 QPushBUtton控件样式 常用子控件 常用伪状态 QSS示例 代码: QPushButton {background-color: #99B5D1;color: white;font-weigth: bold;border-radius: 20px; }QPushButton:hover {background-color: red; }QPushButton:p…

layui动态拼接生成下拉框验证必填项失效问题

利用 jQuery 动态拼接下拉框时&#xff0c;lay-verify"required" 失效了&#xff0c;有以下几种原因。 1. <form></form>标签 加入 layui 类&#xff0c;class"layui-form" 。提交按钮上加自动提交&#xff0c;lay-submit ""; 。需…

Vue 92 ,Element 15 ,Vue + el-upload 实现图片上传与管理

目录 前言 一. 文章背景 二. 项目结构 三. 核心代码解析 1. 页面结构 2. 属性介绍 3. 必要参数 4. 函数逻辑 四. 相关样式布局 五. 关键功能解释 六. 注意事项 七. 本文总结 前言 在这篇博客中&#xff0c;我们将深入探讨如何使用 Vue 和 el-upload 构建一个图片上…

安宝特应用 | 美国OSHA扩展Vuzix AR眼镜应用,强化劳动安全与效率

随着工业技术的进步&#xff0c;如何在保障员工安全的同时提高生产效率成为现代企业面临的重要挑战。 美国劳工部职业安全与健康管理局&#xff08;OSHA&#xff09;于2024年12月2日宣布对Vuzix M400智能眼镜进行扩大部署&#xff0c;代表AR技术正为工业环境下的劳动保护开辟了…

linux socket编程之udp_dict_serve服务端--引入配置文件

注意&#xff1a;本篇博客只是对上一篇博客功能的增加 1.创建配置文件(翻译) Dict.txt apple: 苹果 banana: 香蕉 cat: 猫 dog: 狗 book: 书 pen: 笔 happy: 快乐的 sad: 悲伤的 run: 跑 jump: 跳 teacher: 老师 student: 学生 car: 汽车 bus: 公交车 love: 爱 hate: 恨 hell…