当前位置: 首页 > news >正文

异步javaScript

在本文中,我们将解释什么是异步编程,为什么我们需要它,并简要讨论 JavaScript 历史上异步函数是怎样被实现的。

预备知识:基本的计算机素养,以及对 JavaScript 基础知识的一定了解,包括函数和事件处理程序。
目标:熟悉异步 JavaScript 的概念,了解它与同步 JavaScript 的不同,以及我们需要它的原因。

异步编程技术使你的程序可以在执行一个可能长期运行的任务的同时继续对其他事件做出反应而不必等待任务完成。与此同时,你的程序也将在任务完成后显示结果。

浏览器提供的许多功能(尤其是最有趣的那一部分)可能需要很长的时间来完成,因此需要异步完成,例如:

  • 使用 fetch() 发起 HTTP 请求
  • 使用 getUserMedia() 访问用户的摄像头和麦克风
  • 使用 showOpenFilePicker() 请求用户选择文件以供访问

因此,即使你可能不需要经常实现自己的异步函数,你也很可能需要正确使用它们。

在这篇文章中,我们将从同步函数长时间运行时存在的问题开始,并以此进一步认识异步编程的必要性。

同步编程

观察下面的代码:

const name = "Miriam";
const greeting = `Hello, my name is ${name}!`;
console.log(greeting);
// "Hello, my name is Miriam!"

这段代码:

  1. 声明了一个叫做 name 的字符串常量
  2. 声明了另一个叫做 greeting 的字符串常量(并使用了 name 常量的值)
  3. 将 greeting 常量输出到 JavaScript 控制台中。

我们应该注意的是,实际上浏览器是按照我们书写代码的顺序一行一行地执行程序的。浏览器会等待代码的解析和工作,在上一行完成后才会执行下一行。这样做是很有必要的,因为每一行新的代码都是建立在前面代码的基础之上的。

这也使得它成为一个同步程序

事实上,调用函数的时候也是同步的,就像这样:

function makeGreeting(name) {return `Hello, my name is ${name}!`;
}
const name = "Miriam";
const greeting = makeGreeting(name);
console.log(greeting);
// "Hello, my name is Miriam!"

在这里 makeGreeting() 就是一个同步函数,因为在函数返回之前,调用者必须等待函数完成其工作。

一个耗时的同步函数

如果同步函数需要很长的时间怎么办?

当用户点击“生成素数”按钮时,这个程序将使用一种非常低效的算法生成一些大素数。你可以控制要生成的素数数量,这也会影响操作需要的时间。

<label for="quota">素数个数:</label>
<input type="text" id="quota" name="quota" value="1000000" /><button id="generate">生成素数</button>
<button id="reload">重载</button><div id="output"></div>
function generatePrimes(quota) {function isPrime(n) {for (let c = 2; c <= Math.sqrt(n); ++c) {if (n % c === 0) {return false;}}return true;}const primes = [];const maximum = 1000000;while (primes.length < quota) {const candidate = Math.floor(Math.random() * (maximum + 1));if (isPrime(candidate)) {primes.push(candidate);}}return primes;
}
document.querySelector("#generate").addEventListener("click", () => {const quota = document.querySelector("#quota").value;const primes = generatePrimes(quota);document.querySelector("#output",).textContent = `完成!已生成素数${quota}个。`;
});
document.querySelector("#reload").addEventListener("click", () => {document.location.reload();
});

试着点击“生成素数”按钮。在程序显示“完成!”信息之前可能需要几秒钟(取决于你的电脑性能)。

耗时同步函数的问题

接下来的示例和上一个一样,不过我们增加了一个文本框供你输入。这一次,试着点击“生成素数”,然后在文本框中输入。

你会发现,当我们的 generatePrimes() 函数运行时,我们的程序完全没有反应:用户不能输入任何东西,也不能点击任何东西,或做任何其他事情。

这就是耗时的同步函数的基本问题。在这里我们想要的是一种方法,以让我们的程序可以:

  • 通过调用一个函数来启动一个长期运行的操作
  • 让函数开始操作并立即返回,这样我们的程序就可以保持对其他事件做出反应的能力
  • 当操作最终完成时,通知我们操作的结果。

这就是异步函数为我们提供的能力,本模块的其余部分将解释它们是如何在 JavaScript 中实现的。

事件处理程序

我们刚才看到的对异步函数的描述可能会让你想起事件处理程序,这么想是对的。事件处理程序实际上就是异步编程的一种形式:你提供的函数(事件处理程序)将在事件发生时被调用(而不是立即被调用)。如果“事件”是“异步操作已经完成”,那么你就可以看到事件如何被用来通知调用者异步函数调用的结果的。

一些早期的异步 API 正是以这种方式来使用事件的。XMLHttpRequest API 可以让你用 JavaScript 向远程服务器发起 HTTP 请求。由于这样的操作可能需要很长的时间,所以它被设计成异步 API,你可以通过给 XMLHttpRequest 对象附加事件监听器来让程序在请求进展和最终完成时获得通知。

下面的例子展示了这样的操作。点击“点击发起请求”按钮来发送一个请求。我们将创建一个新的 XMLHttpRequest 并监听它的 loadend 事件。而我们的事件处理程序则会在控制台中输出一个“完成!”的消息和请求的状态代码。

我们在添加了事件监听器后发送请求。注意,在这之后,我们仍然可以在控制台中输出“请求已发起”,也就是说,我们的程序可以在请求进行的同时继续运行,而我们的事件处理程序将在请求完成时被调用。

<button id="xhr">点击发起请求</button>
<button id="reload">重载</button><pre readonly class="event-log"></pre>
const log = document.querySelector(".event-log");
document.querySelector("#xhr").addEventListener("click", () => {log.textContent = "";const xhr = new XMLHttpRequest();xhr.addEventListener("loadend", () => {log.textContent = `${log.textContent}完成!状态码:${xhr.status}`;});xhr.open("GET","https://raw.githubusercontent.com/mdn/content/main/files/en-us/_wikihistory.json",);xhr.send();log.textContent = `${log.textContent}请求已发起\n`;
});
document.querySelector("#reload").addEventListener("click", () => {log.textContent = "";document.location.reload();
});

这就像我们在以前的模块中遇到的事件处理程序,只是这次的事件不是像点击按钮那样的用户行为,而是某个对象的状态变化。

回调

事件处理程序是一种特殊类型的回调函数。而回调函数则是一个被传递到另一个函数中的会在适当的时候被调用的函数。正如我们刚刚所看到的:回调函数曾经是 JavaScript 中实现异步函数的主要方式。

然而,当回调函数本身需要调用其他同样接受回调函数的函数时,基于回调的代码会变得难以理解。当你需要执行一些分解成一系列异步函数的操作时,这将变得十分常见。例如下面这种情况:

function doStep1(init) {return init + 1;
}
function doStep2(init) {return init + 2;
}
function doStep3(init) {return init + 3;
}
function doOperation() {let result = 0;result = doStep1(result);result = doStep2(result);result = doStep3(result);console.log(`结果:${result}`);
}
doOperation();

现在我们有一个被分成三步的操作,每一步都依赖于上一步。在这个例子中,第一步给输入的数据加 1,第二步加 2,第三步加 3。从输入 0 开始,最终结果是 6(0+1+2+3)。作为同步代码,这很容易理解。但是如果我们用回调来实现这些步骤呢?

function doStep1(init, callback) {const result = init + 1;callback(result);
}
function doStep2(init, callback) {const result = init + 2;callback(result);
}
function doStep3(init, callback) {const result = init + 3;callback(result);
}
function doOperation() {doStep1(0, (result1) => {doStep2(result1, (result2) => {doStep3(result2, (result3) => {console.log(`结果:${result3}`);});});});
}
doOperation();

因为必须在回调函数中调用回调函数,我们就得到了这个深度嵌套的 doOperation() 函数,这就更难阅读和调试了。在一些地方这被称为“回调地狱”或“厄运金字塔”(因为缩进看起来像一个金字塔的侧面)。

面对这样的嵌套回调,处理错误也会变得非常困难:你必须在“金字塔”的每一级处理错误,而不是在最高一级一次完成错误处理。

由于以上这些原因,大多数现代异步 API 都不使用回调。事实上,JavaScript 中异步编程的基础是 Promise,这也是我们下一篇文章要讲述的主题。

相关文章:

异步javaScript

在本文中&#xff0c;我们将解释什么是异步编程&#xff0c;为什么我们需要它&#xff0c;并简要讨论 JavaScript 历史上异步函数是怎样被实现的。 预备知识&#xff1a;基本的计算机素养&#xff0c;以及对 JavaScript 基础知识的一定了解&#xff0c;包括函数和事件处理程序…...

看跨境电商世界区域分布,Live Market教你深入参与跨境创业

随着全球化发展带来互联网技术的进步和平台经济的触角伸向全球&#xff0c;跨境电商越来越成为全球贸易的重要组成部分。根据国际数据公司&#xff08;IDC&#xff09;的最新数据显示&#xff0c;全球前五大跨境电商平台分别是亚马逊、阿里巴巴、eBay、Wish和京东全球购。这五家…...

python中的装饰器的真正含义和用法

闭包&#xff1a; 闭包是python中的一个很实用的写法&#xff0c;可以使得用户在函数中调用该函数外的函数的变量&#xff0c;使得该变量常驻于内存中。 闭包函数&#xff1a; 输入是函数&#xff0c;输出也是一个函数。 装饰器的写法是python闭包的语法糖。 面试中经常面…...

opencv基础-38 形态学操作-闭运算(先膨胀,后腐蚀)cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)

闭运算是先膨胀、后腐蚀的运算&#xff0c;它有助于关闭前景物体内部的小孔&#xff0c;或去除物体上的小黑点&#xff0c;还可以将不同的前景图像进行连接。 例如&#xff0c;在图 8-17 中&#xff0c;通过先膨胀后腐蚀的闭运算去除了原始图像内部的小孔&#xff08;内部闭合的…...

RocketMQ生产者和消费者都开启Message Trace后,Consume Message Trace没有消费轨迹

一、依赖 <dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-spring-boot-starter</artifactId><version>2.0.3</version> </dependency>二、场景 1、生产者和消费者所属同一个程序 2、生产者开启消…...

JDV背后的技术-助力618 | 京东云技术团队

一、项目介绍 JDV&#xff08;可视化大屏&#xff09;是京东内部搭建可视化大屏的数据工具平台&#xff0c;内置10种模版特效&#xff0c;40种风格各异的图表、导航等组件。与集团其他数据工具打通&#xff0c;支持一站式、自助化、拖拽式搭建大屏&#xff0c;实现数据切换、联…...

0基础学习VR全景平台篇 第78篇:全景相机-拍摄VR全景

新手入门圆周率科技&#xff0c;成立于2012年&#xff0c;是中国最早投身嵌入式全景算法研发的团队之一&#xff0c;亦是全球市场占有率最大的全景算法供应商。相继推出一体化智能屏、支持一键高清全景直播的智慧全景相机--Pilot Era和Pilot One&#xff0c;为用户带来实时畅享…...

Spring MVC简介与概述

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…...

java基础复习(第六日)

java基础复习(五) 1.是否了解类似 RabbitMQ.kalka 之类的队列服务? 请简述队列取务中的常见要素和使用场景&#xff1f; 了解&#xff0c;队列服务是一种应用间的通信方式&#xff0c;可以实现异步处理、应用解耦、流量削峰和消息通信等功能 队列服务的常见要素&#xff1a…...

商用服务机器人公司【Richtech Robotics】申请纳斯达克IPO上市

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;总部位于美国内华达州拉斯维加斯由华人领导的商用服务机器人公司【Richtech Robotics】近期已向美国证券交易委员会&#xff08;SEC&#xff09;提交招股书&#xff0c;申请在纳斯达克IPO上市&am…...

关于nn.Embedding如何使用预定义词表

直接使用&#xff0c;则是没有pretrained的词表。 若要使用预定义词表&#xff0c;则可以用 pretrained_weight np.array(pretrained_weight) embeds.weight.data.copy_(torch.from_numpy(pretrained_weight))参考&#xff1a; https://wmathor.com/index.php/archives/1435/…...

怎么设置文件夹密码?文件夹密码设置方法合集

为文件夹设置密码可以有效地保护文件夹的数据安全&#xff0c;那么该怎么设置文件夹密码呢&#xff1f;下面我们来一起了解一下。 文件夹保护3000 想要简单快捷的为文件夹设置密码&#xff0c;那么&#xff0c;文件夹保护3000就是最佳的选择。它提供了3种文件夹保护方式&#…...

PEMFC氢氧质子交换燃料电池MATLAB仿真模型

氢氧燃料电池静态模型&#xff1a; &#xff08;1&#xff09;热力学电动势En &#xff08;2&#xff09;活化极化过电势Vact 活化损失主要是因为电极表面的反应速度过慢&#xff0c;在驱动电子传递到或者传送出电极的化学反应时&#xff0c;部分电压会被消耗。 &#xff08;…...

创建PVC注意事项

On the one hand 创建永久卷&#xff08;Persistent Volume Claim&#xff0c;PVC&#xff09;时需要考虑以下几个因素&#xff1a; 存储类别&#xff08;Storage Class&#xff09;&#xff1a;选择适合需求的存储类别是创建 PVC 的第一步。存储类别定义了永久卷的属性&…...

Sencha Ext.NET Crack 快速应用程序的正确工具集

Sencha Ext.NET Crack 快速应用程序的正确工具集 Sencha Ext.NET是一个高级的ASP.NET核心组件框架&#xff0c;它包含了强大的跨浏览器Sencha Ext JS库。通过140多个预构建和专业测试的UI组件实现企业级性能和生产效率。Sencha Ext.NET使用尖端的Web技术创建功能强大的Web应用程…...

transformer学习

transformer 李宏毅老师的课&#xff1a;https://www.youtube.com/watch?vugWDIIOHtPA&listPLJV_el3uVTsOK_ZK5L0Iv_EQoL1JefRL4&index60 知乎上的文章&#xff1a;Transformer模型详解&#xff08;图解最完整版&#xff09; 主要参考tensorflow的官方文档&#xf…...

基于LNMP架构搭建Discuz论坛

LNMP: L---->linux系统&#xff0c;操作系统。 N----->nginx网站服务&#xff08;前端),提供前端的静态页面服务。同时具有代理、转发的作用。&#xff08;转发就是转发后端请求&#xff0c;转发PHP&#xff09;&#xff0c;nginx没有处理动态资源的功能&#xff0c;他有…...

乐鑫科技2021笔试题

笔试时间&#xff1a;2020.09.09&#xff0c;10&#xff1a;00-11&#xff1a;30 岗位&#xff1a;嵌入式软件工程师 题型&#xff1a;单选题20道&#xff0c;40分。编程题2道&#xff0c;60分。 单选题 1、算术右移指令执行的操作是&#xff1f;符号位会变化吗&#xff1f…...

VL 模型 Open-Set Domain Adaptation with Visual-Language Foundation Models 论文阅读笔记

Open-Set Domain Adaptation with Visual-Language Foundation Models 论文阅读笔记 一、Abstract 写在前面 又是一周周末&#xff0c;在家的时间感觉过得很快呀。今天没得时间写博客&#xff0c;留下个标题&#xff0c;明天搞完。 论文地址&#xff1a;Open-Set Domain Adapta…...

在IDEA同一个窗口中同时打开多个独立项目

文章说明 本文主要说明如何在Intellij Idea中同时打开多个独立的Maven项目。 我在使用idea的时候&#xff0c;由于自己负责了很多项目&#xff0c;经常要在不通的代码之间切换来切换去。然后搜索代码的时候也只能搜到当前打开的这个项目。因为这个原因&#xff0c;一些小项目…...

SwitchyOmega+Burp无感抓包实战:解决HTTPS拦截与流量路由难题

1. 为什么“无感抓包”是BurpSuite日常使用的分水岭刚接触Web安全测试的朋友常有个错觉&#xff1a;装上Burp Suite&#xff0c;配好代理&#xff0c;打开浏览器&#xff0c;点几下网页——流量就该自动进来了。结果现实是&#xff1a;首页打不开、登录态丢失、HTTPS报错满屏、…...

古戏台构件声学特性的时域有限差分方法【附模型】

✨ 长期致力于时域有限差分法、窑洞、戏台、八字墙、共形技术研究工作&#xff0c;擅长数据搜集与处理、建模仿真、程序编写、仿真设计。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流&#xff0c;点击《获取方式》 &#xff08;1&#xff09;曲面共形网格快速生成算法&#xff1a; …...

[智能体-69]:重新认知MCP:协议不生产智能,只是AI全域交互的标准化基石

MCP只是提供了大模型、编排调度、外部工具能够进行结构化交流的标准&#xff0c;而整个系统的智能主要依赖编排调度&#xff0c;与外部软件系统的交互取决于外部工具&#xff0c;包括外部语音交互、视觉交互、数字化交互。当下MCP&#xff08;Model Context Protocol&#xff0…...

收藏必看|2026 版大厂 AI 岗位薪资曝光!普通程序员转型大模型最全指南

深夜收到大厂 HR 好友发来的内部资料&#xff0c;再三叮嘱切勿对外泄露。如今网络信息传播速度极快&#xff0c;这份 2026 年企业 AI 岗真实薪资内幕&#xff0c;也值得给广大程序员、零基础入行小白参考借鉴。 翻看完整薪资台账后&#xff0c;真切感受到当下大模型赛道的薪资差…...

Allegro PCB设计小技巧:如何让Route Keepout区域既能走线又能打过孔(附详细步骤图)

Allegro PCB设计实战&#xff1a;Route Keepout区域的灵活控制技巧 在高速PCB设计中&#xff0c;Route Keepout区域的管理常常让工程师陷入两难境地——元件封装自带的限制区域与实际布线需求产生冲突。特别是处理PCIE等高速信号时&#xff0c;这种矛盾尤为突出。传统做法要么完…...

5个必知的Universal-Updater高级功能:从QR扫描到后台安装

5个必知的Universal-Updater高级功能&#xff1a;从QR扫描到后台安装 【免费下载链接】Universal-Updater An easy to use app for installing and updating 3DS homebrew 项目地址: https://gitcode.com/gh_mirrors/un/Universal-Updater Universal-Updater是一款专为任…...

全球无障碍宣传日:iOS 26 辅助功能大升级,这些实用小功能你用过吗?

辅助功能发展与升级很多人对辅助功能的印象还停留在 "小白点"&#xff0c;但随着 iPhone 进入全面屏时代&#xff0c;它逐渐变得陌生。实际上&#xff0c;Apple 每年都会为其增添功能&#xff0c;方便身体有障人士使用 iPhone。而且&#xff0c;这些功能不仅惠及有障…...

别再死记公式了!用Python手写一个卷积层,彻底搞懂CNN里的‘卷’是怎么算的

用Python手写卷积层&#xff1a;从零理解CNN的"卷"运算 当你第一次看到卷积神经网络(CNN)的数学公式时&#xff0c;那些复杂的符号和下标是否让你望而却步&#xff1f;作为计算机视觉领域的基石&#xff0c;CNN的核心在于理解卷积运算的本质。本文将带你用NumPy从零实…...

5A智慧景区建设|对标一流!巨有科技打造数智化标杆景区

5A级景区是中国旅游的最高标准&#xff0c;代表着服务与管理的顶尖水平。随着5A评审标准日益严苛&#xff0c;“智慧化”已成为核心硬性指标。然而&#xff0c;不少景区的智慧化建设陷入“重硬件、轻整合”的误区&#xff0c;系统林立、数据孤岛&#xff0c;投入巨大却效果不佳…...

集成Taotoken为OpenClaw工作流提供持久化模型支持

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 集成Taotoken为OpenClaw工作流提供持久化模型支持 在构建基于OpenClaw的自动化Agent工作流时&#xff0c;一个稳定且可灵活切换的模…...