深入理解 JavaScript 中的异步编程

深入理解 JavaScript 中的异步编程

一、引言

在 JavaScript 编程的世界里,异步编程是一个至关重要且充满魅力的概念。随着现代 Web 应用程序的复杂性不断增加,对异步操作的需求也日益凸显。无论是处理用户交互、网络请求还是文件读取,异步编程都发挥着关键作用。它允许我们的程序在等待某些耗时操作完成时,不会阻塞其他代码的执行,从而提高了应用程序的响应能力和性能。在这篇博客中,我们将深入探讨 JavaScript 中的异步编程,包括它的来历、概念、实现方式以及相关的进程与线程知识。

二、异步是什么

(一)简单示例与分析

在 JavaScript 中,异步操作与同步操作有着明显的区别。看下面的代码示例:

// 异步
let a = 1;
setTimeout(() => {a += 1;console.log('out', a);
}, 1000);
console.log('end', a);
// end 1
// out 2

在这个例子中,setTimeout是一个典型的异步函数。当 JavaScript 引擎执行到setTimeout时,它不会等待setTimeout中的回调函数执行完再继续向下执行,而是直接执行console.log('end', a)。这是因为setTimeout将回调函数放入了一个特殊的队列(我们稍后会详细介绍这个队列),然后 JavaScript 引擎继续执行后续代码。当经过指定的时间(这里是 1000 毫秒)后,回调函数才会被从队列中取出并执行。

再看另一个示例:

// 循环执行
let a = 1;
let timer = setInterval(() => {a += 1;console.log('out', a);
}, 1000);setTimeout(() => {clearInterval(timer);console.log('end', a);
}, 3000);// out 2
// out 3
// end 3

这里同时使用了setIntervalsetTimeoutsetInterval会每隔 1000 毫秒重复执行一次回调函数,不断地增加a的值并输出。而setTimeout在 3000 毫秒后清除setInterval。在这个过程中,setInterval的执行是异步的,它不会阻塞其他代码的执行。

(二)异步操作背后的机制

对于前面提到的问题,为何eg2interval会执行,而eg1中没有类似的“等待执行”问题呢?这涉及到 JavaScript 的事件循环机制。

当我们使用setTimeoutsetInterval这样的定时器函数时,它们创建的任务被放入了一个定时器队列(这是一个我们看不到的队列)。JavaScript 引擎有一个主执行线程,它按照代码的顺序执行同步代码。当遇到异步函数时,比如setTimeout,它只是安排了一个在未来某个时间执行的任务,然后继续执行后续的同步代码。在主执行线程空闲时,事件循环会检查定时器队列,如果有任务的时间已经到达,就会将任务放入主执行线程执行。setInterval则是不断地在定时器队列中添加任务,只要不被清除,就会按照指定的时间间隔持续添加。

(三)浏览器中的进程与线程

在面试中,常常会问到在浏览器中新开一个窗口是进程还是线程的问题。这涉及到进程和线程的概念。

进程

进程是 CPU 资源分配的基本单位,一个进程包含若干个线程。它与程序有以下区别:

  • 定义不同:进程是动态的,它代表了程序在内存中的一次执行过程,有自己的生命周期,包括创建、就绪、运行、阻塞和结束五种状态。而程序是静态的,是一组指令的集合,存储在磁盘上。
  • 资源分配:同一进程的各线程共享本进程的资源。进程是系统资源分配的基本单位,它拥有独立的内存空间、文件描述符等资源。
  • 状态不同:进程有运行、就绪和阻塞三种基本状态,这些状态反映了进程在 CPU 上的执行情况以及是否在等待某些资源。
线程

线程是进程的执行单元,是 CPU 调度的最小单位,一个进程中可以有多个线程。线程与进程的区别如下:

  • 地址空间和资源:进程间相互独立,每个进程都有自己独立的地址空间和系统资源。而同一进程的各线程共享进程的地址空间和资源,如内存、文件句柄等。
  • 执行过程:同一进程内的线程共享代码段(包括代码、常量、数据结构等),但每个线程有独立的运行栈和程序计数器(PC)。这意味着每个线程都有自己的执行路径和局部变量,但共享进程中的大部分数据。线程是 CPU 调度执行的基本单位,这使得多线程可以在一个进程内并发执行,提高程序的执行效率。

三、异步编程在 JavaScript 中的实现

(一)回调函数

回调函数是 JavaScript 中实现异步编程的一种常见方式。我们已经在setTimeoutsetInterval中看到了回调函数的使用。除了定时器,许多异步操作都使用回调函数。例如,在进行网络请求时:

function handleResponse(data) {console.log('Received data:', data);
}function makeRequest(url, callback) {// 这里模拟一个异步网络请求,实际中会使用 XMLHttpRequest 或 fetch 等setTimeout(() => {const data = { message: 'Hello from server' };callback(data);}, 2000);
}makeRequest('https://example.com', handleResponse);
console.log('Request sent.');
// Request sent.
// Received data: { message: 'Hello from server' }

在这个例子中,makeRequest函数接受一个 URL 和一个回调函数。它模拟了一个异步网络请求,在 2000 毫秒后调用回调函数,并传递请求得到的数据。这种方式使得代码可以在请求进行的同时继续执行其他操作,而不会被阻塞。

(二)Promise

Promise 是 JavaScript 中更现代的异步编程解决方案。它提供了一种更优雅的方式来处理异步操作,避免了回调地狱的问题。

function makeRequest(url) {return new Promise((resolve, reject) => {// 模拟异步请求setTimeout(() => {const data = { message: 'Hello from server' };resolve(data);}, 2000);});
}makeRequest('https://example.com')
.then(data => console.log('Received data:', data))
.catch(error => console.log('Error:', error));
console.log('Request sent.');
// Request sent.
// Received data: { message: 'Hello from server' }

在这个Promise示例中,makeRequest函数返回一个Promise对象。当异步操作成功完成时,我们调用resolve函数,将结果传递给then方法中的回调函数。如果出现错误,可以调用reject函数,由catch方法处理错误。Promise的链式调用使得异步代码的逻辑更加清晰。

(三)async/await

async/await是基于Promise的更高级的异步编程语法糖。它使得异步代码看起来更像同步代码,提高了代码的可读性。

async function getData() {try {const response = await makeRequest('https://example.com');console.log('Received data:', response);} catch (error) {console.log('Error:', error);}
}getData();
console.log('Function called.');
// Function called.
// Received data: { message: 'Hello from server' }

async函数中,我们可以使用await关键字等待一个Promise的结果。这样的代码结构更符合人类的思维方式,让异步编程变得更加容易理解和维护。

四、总结

JavaScript 中的异步编程是现代 Web 开发中不可或缺的一部分。通过理解异步的概念、背后的机制以及各种实现方式,我们能够更好地编写高效、响应迅速的应用程序。从简单的回调函数到更先进的Promiseasync/await,这些技术为我们处理异步操作提供了丰富的工具。同时,了解进程和线程的基础知识有助于我们理解异步操作在浏览器环境中的运行原理。在实际开发中,我们需要根据具体的场景选择合适的异步编程方式,以确保代码的质量和可维护性。希望这篇文章能够帮助你深入理解 JavaScript 中的异步编程,让你在编程之路上更进一步。

无论是构建复杂的单页应用程序还是简单的网页交互,异步编程的知识都将成为你手中的利器,帮助你应对各种挑战,创造出更加流畅和高效的用户体验。如果你有任何问题或者新的见解,欢迎在评论区交流,让我们一起探索 JavaScript 异步编程的更多奥秘。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

深度学习之其他常见的生成式模型

1.1 什么是自回归模型:pixelRNN与pixelCNN? ​ 自回归模型通过对图像数据的概率分布 p d a t a ( x ) p_{data}(x) pdata​(x)进行显式建模,并利用极大似然估计优化模型。具体如下: p d a t a ( x ) ∏ i 1 n p ( x i ∣ x 1 …

短期电力负荷(论文复现)

✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨ 🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢,在这里我会分享我的知识和经验。&am…

DBeaver如何设置自动刷新数据库表的数据,彻底解放双手!

前言 大家好,我是小徐啊。 DBeaver是一款常用的数据库连接工具,它的优点是免费使用,而且支持的数据库类型超级多,甚至可以直接安装数据库对应的驱动jar包来连接数据库。 比如达梦数据库,之前版本是可以通过jar包方式…

黄仁勋:AI革命将创百万亿美元价值!近屿智能带你入局AIGC

11月13日,NVIDIA在日本成功举办了2024年AI峰会。一场关于人工智能驱动的新工业革命的讨论热烈展开。英伟达创始人兼CEO黄仁勋与软银主席兼CEO孙正义共同探讨了当前技术革命的独特之处及其深远影响。 黄仁勋在会上表示,AI革命将创造的价值不是以万亿美元计…

知网翻译助手及其10款翻译工具使用体验大PK!!!

在这个信息爆炸的时代,翻译工具成了我们日常工作中不可或缺的得力助手。作为一个经常需要处理多语言文件的人,翻译工具对我来说简直是救命稻草。除了知网助手外,我还用过不少翻译软件,现在,我就来说说知网翻译助手和其…

Entity Framework的简单使用案例

需要引入的框架: 实体类: [Table("Users")] internal class User {[Key]public int Id { get; set; }[Required][StringLength(100)][Index(IsUnique true)]public string Username { get; set; }[Required][StringLength(100)]public strin…

Scroll 生态全面启动为 Pencils Protocol 赋能,DAPP 将迎强势腾飞

​Pencils Protocol 是 Scroll 生态最大的综合性 DeFi 平台,随着 DAPP 通证面向市场,Pencils Protocol 生态经济体系也将迎来全面运转。目前,DAPP 通证已经陆续上线了 Gate、Kucoin、Bitget、Coinone 等主流交易市场,全球用户能够…

【英特尔IA-32架构软件开发者开发手册第3卷:系统编程指南】2001年版翻译,2-23

文件下载与邀请翻译者 学习英特尔开发手册,最好手里这个手册文件。原版是PDF文件。点击下方链接了解下载方法。 讲解下载英特尔开发手册的文章 翻译英特尔开发手册,会是一件耗时费力的工作。如果有愿意和我一起来做这件事的,那么&#xff…

CPLD架构

1. 通用CPLD构架 传统的CPLD内部构架布局如图1-1所示,可编程互连阵列(PIA)在芯片中心位置,而逻辑阵列块则在芯片四周靠近I/O模块。目前大多数的CPLD都是采用这种结构,包括Xilinx主流的CoolRunner系列和Altera MAX 300…

2024第十四届新华三杯预赛考试大纲

本文档取自新华三杯官方网站

类与对象

类: class默认私有,struct默认公有 面向对象的三大特性: 封装、继承、多态 封装:本质是一种管控;C数据和方法都放在类里面,使用访问限定符对成员限制 类的存储: 每个对象只存成员变量&#…

elf文件简单介绍

文章目录 elf 程序示意图ELF文件格式概述ELF的组成结构1. ELF头部(ELF Header)2. 程序头表(Program Header Table)与程序头项(Program Header Entry)3. 节区头表(Section Header Table&#xff…

【python系列】开篇:自学python的方法

1.前言 唯有自学才是最高效最省钱的学习编程的方法。最高效是因为你可以按照自己的节奏来进行学习,随时随地随心的学习,最主要的是掌握学习方法,当然培训老师是不会告诉你方法的,总是跟着培训老师在盲人摸象。最省钱是不用投入资…

【论文复现】交通路口智能监测平台实现

📝个人主页🌹:Eternity._ 🌹🌹期待您的关注 🌹🌹 ❀交通路口智能监测平台实现 1.概述2.工程文件简介2.1 工程文件结构2.2 训练检测模型2.2.1 准备数据集2.2.2 训练自己的权重文件2.2.3 使用自己…

不宽的宽字符

根据提示&#xff0c;通过nc 202.38.93.141 14202来进行连接&#xff0c;可以用自己的机器进行连接&#xff0c;也可以直接点击“打开/下载题目”连接&#xff1a; 意料之中的无法打开flag&#xff0c;看来得下载附件看看源码了 #include <iostream> #include <fstrea…

无脑使用matlab运行YOLOv5模型,实现目标检测

文章目录 前言代码报错解决方法缺点总结 前言 YOLO 是一种经典的一阶段目标检测算法&#xff0c;它将检测问题转化为回归问题。与 Faster R-CNN 不同&#xff0c;YOLO 不是提取 RoI,而是直接通过回归的方法生成每个类的边界框坐标和概率。与 Faster R-CNN相比&#xff0c;大大…

java ssm 高校固定资产管理系统 高校物资管理 资产信息 源码 jsp

一、项目简介 本项目是一套基于SSM的高校固定资产管理系统&#xff0c;主要针对计算机相关专业的和需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、数据库脚本、软件工具等。 项目都经过严格调试&#xff0c;确保可以运行&#xff01; 二、技术实现 ​后端技术&am…

《战国王朝》青铜材料具体作用介绍

《战国王朝》中的青铜材料是游戏里非常重要的金属材料&#xff0c;而青铜材料的具体作用就是青铜用于制作第三层次的工具和武器;它比铜制的更好&#xff0c;但不如铁和钢制的&#xff0c;相比石制和铜制工具&#xff0c;青铜物品的使用寿命更长。 战国王朝青铜材料有什么用 青…

unity3d————延时函数

1.public void InvokeRepeating(string methodName, float time, float repeatRate); 延迟重复执行函数 InvokeRepeating 参数一&#xff1a;函数名字符串 参数二&#xff1a;第一次执行的延迟时间 参数三&#xff1a;之后每次执行的间隔时间 注意&#xff1a; 1-1.延时函数第…

焊接手电钻板子后总结

复用旧工程部分方案注意事项&#xff1a; 粘贴暑假时候做的工程原理图&#xff0c;复制到现在的项目中竟然忘记修改3V3的名称&#xff0c;导致3V3MCU与3V3的区别&#xff0c;这个错误以后一定要注意&#xff1a; 现在工程中的供电3V3&#xff0c;不是3V3MCU: 焊接QFN芯片&…