JavaScript中的异步编程

2023-10-27

当我们在编写JavaScript代码时,经常会遇到需要执行长时间运行的任务的情况,例如从服务器获取数据或进行复杂的计算。在这些情况下,我们不希望阻塞用户界面,因为这会使网站看起来卡顿,甚至无响应。为了避免这种情况,我们需要使用JavaScript中的异步编程技术。

异步编程是JavaScript中的一个核心概念,它使我们能够在执行长时间运行的任务时不会阻塞用户界面,而是在任务完成后立即返回结果。本文将介绍JavaScript中的异步编程方式,并探讨它们的优缺点,以及如何使用它们来解决常见的异步编程问题。

一、回调函数

回调函数是JavaScript中最早和最基本的异步编程方式。它通过在函数参数中传递一个函数,让我们能够在异步操作完成后调用该函数。例如,我们可以使用XMLHttpRequest对象从服务器获取数据:

var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://example.com/data');
xhr.onreadystatechange = function() {
  if (xhr.readyState === 4 && xhr.status === 200) {
    console.log(xhr.responseText);
  }
};
xhr.send();

在上面的例子中,我们定义了一个XMLHttpRequest对象,然后使用open()方法设置请求的类型和URL。然后,我们为onreadystatechange属性指定了一个函数,当readyState属性变为4且状态码为200时,该函数将被调用。在该函数中,我们可以访问响应文本并在控制台中打印它。

虽然回调函数是JavaScript中最早和最基本的异步编程方式,但它有一些缺点。首先,如果我们需要进行嵌套异步操作,回调函数将变得非常复杂和难以理解。其次,回调函数容易出现回调地狱问题,这是指代码中有太多的回调函数,使得代码难以维护和扩展。

二、Promise

为了解决回调地狱问题,JavaScript引入了Promise,它是一种更加高级的异步编程方式。Promise通过将异步操作的结果封装在一个对象中,使得我们可以更加清晰和简洁地处理异步操作。例如,我们可以使用Promise从服务器获取数据:

fetch('https://example.com/data')
  .then(response => response.text())
  .then(text => console.log(text))
  .catch(error => console.error(error));

在上面的例子中,我们使用fetch()方法发起一个HTTP请求,并将其封装在一个Promise对象中。然后,我们使用.then()方法指定一个函数,当Promise对象的状态变为fulfilled时将被调用。在这个函数中,我们可以访问响应对象并将其转换为文本。然后,我们使用.then()方法指定另一个函数,当上一个Promise对象的状态变为fulfilled时将被调用。在这个函数中,我们可以访问响应文本并在控制台中打印它。最后,我们使用.catch()方法指定一个函数,当Promise对象的状态变为rejected时将被调用。在这个函数中,我们可以处理错误。

Promise还提供了一些其他的方法,如Promise.all()和Promise.race()。Promise.all()可以同时处理多个Promise对象,并在所有Promise对象都变为fulfilled时返回一个包含所有结果的数组。例如:

Promise.all([
  fetch('https://example.com/data1'),
  fetch('https://example.com/data2')
])
  .then(responses => Promise.all(responses.map(response => response.text())))
  .then(texts => console.log(texts))
  .catch(error => console.error(error));

在上面的例子中,我们使用Promise.all()方法同时发起两个HTTP请求,并将它们封装在一个数组中。然后,我们使用.then()方法指定一个函数,该函数将结果数组作为参数,并使用Promise.all()方法将结果数组中的所有响应对象转换为文本。最后,我们使用.then()方法指定另一个函数,该函数将文本数组作为参数并在控制台中打印它们。

Promise.race()可以处理多个Promise对象,并在第一个Promise对象变为fulfilled或rejected时返回它的结果。例如:

Promise.race([
  new Promise(resolve => setTimeout(() => resolve('foo'), 2000)),
  new Promise((resolve, reject) => setTimeout(() => reject(new Error('bar')), 1000))
])
  .then(result => console.log(result))
  .catch(error => console.error(error));

在上面的例子中,我们使用Promise.race()方法处理两个Promise对象,其中一个会在2秒后返回字符串'foo',另一个会在1秒后返回一个错误对象。由于第二个Promise对象先返回结果,所以Promise.race()返回错误对象并在.catch()方法中处理它。

三、async/await

async/await是ES2017中引入的一种异步编程方式,它建立在Promise之上,并提供了更加简洁和直观的语法。async/await使用async函数来表示异步操作,并使用await关键字来等待Promise对象的完成。例如,我们可以使用async/await从服务器获取数据:

async function getData() {
  try {
    const response = await fetch('https://example.com/data');
    const text = await response.text();
    console.log(text);
  } catch (error) {
    console.error(error);
  }
}
getData();

在上面的例子中,我们定义了一个async函数getData(),并在其中使用await关键字等待fetch()方法返回一个响应对象。然后,我们再次使用await关键字等待将响应对象转换为文本。最后,我们可以在控制台中打印文本或处理错误。

与Promise一样,async/await也支持多个异步操作的处理。例如,我们可以使用Promise.all()和async/await同时处理多个Promise对象:

async function getData() {
  try {
    const responses = await Promise.all([
      fetch('https://example.com/data1'),
      fetch('https://example.com/data2')
    ]);
    const texts = await Promise.all(responses.map(response => response.text()));
    console.log(texts);
  } catch (error) {
    console.error(error);
  }
}
getData();


在上面的例子中,我们定义了一个async函数getData(),并在其中使用Promise.all()方法同时发起两个HTTP请求并等待它们完成。然后,我们使用await关键字等待将响应对象转换为文本,并将所有结果放入一个数组中。最后,我们可以在控制台中打印文本数组或处理错误。

总结

JavaScript是一门强大的编程语言,具有异步编程的优势。在本文中,我们介绍了三种常见的异步编程方式:回调函数、Promise和async/await。回调函数是异步编程的基础,但它的嵌套结构和错误处理使得代码难以维护。Promise是回调函数的一种改进,它通过链式调用和错误处理提供了更好的可读性和可维护性。最后,async/await建立在Promise之上,提供了更加简洁和直观的语法。当我们需要处理多个异步操作时,Promise.all()和Promise.race()提供了一种有效的方法。无论是哪种方式,我们都可以在JavaScript中使用异步编程来实现更好的性能和用户体验。
 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JavaScript中的异步编程 的相关文章

  • 我如何能够以两行显示标题,并且每行的字体大小不同?

    我正在使用 Google Chart API 创建时间线图 并希望将图的标题修改为两行 问题 我如何能够显示具有不同字体大小的两线图表标题 电流输出 理想输出 相关研究 我唯一能找到的是有人试图用饼图来做到这一点 但我尝试了但无法使其发挥作
  • 如何使用 JavaScript 创建链接?

    我有一个标题字符串和一个链接字符串 我不知道如何将两者放在一起以使用 JavaScript 在页面上创建链接 任何帮助表示赞赏 我试图解决这个问题的原因是因为我有一个 RSS 源并且有一个标题和 URL 列表 我想将标题链接到 URL 以使
  • 渲染货币和符号并与来自不同单元格的数据相结合

    我正在使用最新的 jQuery DataTables v1 10 7 我正在尝试将数字解析为以下格式 239 90 USD 我可以使用此命令使货币正常工作 columns data Price render fn dataTable ren
  • 为什么 iife 在一个简单的例子中不起作用?

    我不明白为什么函数表达式调用不起作用并抛出错误 你能给我解释一下吗 var a function x alert x function a 1 谢谢大家 任务比我想象的要容易得多 这是因为 JS 将 IIFE 解析为函数的参数调用 这样做时
  • 如何将内联 JavaScript 与 Express/Node.js 中动态生成的内容分开?

    对于具有几年 Web 开发经验但没有找到答案的人来说 这是一个有点菜鸟的问题程序员堆栈交换 or Google 我决定在这里问一下 我在用Express网络框架Node js 但这个问题并不特定于任何 Web 框架或编程语言 以下是从数据库
  • 带有淘汰赛js的隐形recaptcha

    我正在完成隐形验证码 但我在实现它时遇到问题 谷歌开发人员页面中的代码显示它应该是这样的
  • React-Redux:state.setIn() 和 state.set() 有什么区别?

    我见过使用setIn and set 在一些react redux代码中 state setIn state set 我在这里找到了一些文档https facebook github io immutable js https facebo
  • 有没有办法使用 Rspec/Capybara/Selenium 将 javascript console.errors 打印到终端?

    当我运行 rspec 时 是否可以让 capybara selenium 向 rspec 报告任何 javascript console errors 和其他异常 我有一大堆测试失败 但当我手动测试它时 我的应用程序正在运行 如果不知道仅在
  • 尝试将数据存储在点击器网站中

    我正在尝试存储一个名为的变量score无论何时刷新 您都会一次又一次地使用它 我不明白的是它的代码是什么 我尝试了一些方法 但似乎都不起作用 这是我的答题器网站 但是当我尝试使用 JavaScript 来存储它时 它不起作用window o
  • 如何制作没有 ng-repeat 的模板并使用 Angular-drag-and-drop-lists 将数据传递到 $scope?

    我想用角度拖放列表 https github com marceljuenemann angular drag and drop lists使用我自己的网格模板到所见即所得编辑器 如何构建我自己的 HTML 模板而不需要ng repeat因
  • 使用 CSS 或 Javascript 填充动画

    我只是想知道是否可以使用 CSS 或 javascript 创建填充动画 基本上我想创建一个填充动画 如下图所示 http i40 tinypic com eit6ia png http i40 tinypic com eit6ia png
  • 如何解决 Typescript 构建中的错误“找不到模块 'jquery'”

    我目前在 ts 文件的顶部有这个import require jquery 我这样做是因为我试图在我的打字稿文件中使用 jquery 但我似乎无法编译它 因为它返回标题中所述的错误 我正在使用 ASP NET CORE 脚本文件夹 tsco
  • 在移动设备上滚动

    这个问题更多的是一个建议研究 我确实希望它对其他人有帮助 并且它不会关闭 因为我不太确定在哪里寻求有关此事的建议 在过去的 6 个月里 我一直在进行移动开发 我有机会处理各种设备上的各种情况和错误 最麻烦的是滚动问题 当涉及到在网站的多个区
  • 对于只触及我的工作表的 Google 表格脚本,收到“此应用程序未经验证”

    我正在编写一个 Google Sheets 脚本 我只想访问与 gs 文件关联的同一电子表格中的数据 似乎我应该有权在自己的电子表格中运行脚本 但是每当我运行一个函数时 我都会得到一个This app isn t verified信息 我该
  • 如何使用 crypto-js 解密 AES ECB

    我正在尝试将加密数据从 flash 客户端 发送到服务器端的 javascript 在 asp 中作为 jscript 运行 有几个 javascript Aes 库 但它们实际上没有文档记录 我正在尝试使用 crypto js 但无法让代
  • 在 Shopify 商店中嵌入 Vue 组件

    在产品页面中 我尝试显示自定义 Vue 组件 为简洁起见 该组件根据给定的产品 ID 显示 Firebase 数据库中的一些信息 我最初尝试将其制作为 Shopify 应用程序 以便我可以访问他们的 API 我实现了 OAuth 并且可以检
  • 如何隐藏/禁用 Highcharts.js 中的图例框?

    我想问是否可以使用 HighCharts js 库隐藏图表中的所有图例框 var chart object chart renderTo render to type graph type colors graph colors title
  • 带参数的事件监听器

    我想将参数传递给 JavaScript 中的事件侦听器 我已经找到了解决方案 但我无法理解它们为什么或如何工作以及为什么其他解决方案不起作用 我有 C C 背景 但是 Javascript 函数的执行有很大不同 您能否帮助我理解以下示例如何
  • 用于交互式图形绘制的轻量级 JavaScript 库? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我有兴趣了解用于绘制交互式图表的最轻量级 javascript 库 我掌握的数据主要是与海洋研究相关的科学数据 我知道一些 jquery
  • JavaScript 相对路径

    在第一个 html 文件中 我使用了一个变量类别链接 var categoryLinks Career prospects http localhost Landa DirectManagers 511 HelenaChechik Dim0

随机推荐

  • HASH函数

    散列函数代表除了对称和非对称加密之外的第三种加密类型 我们可以称之为无密钥加密 hash函数就是把任意长的输入位 或字节 变化成固定长的输出字符串的一种函数 输出字符串的长度称为hash函数的位数 哈希不能用于发现原始消息的内容或其任何其他
  • 微服务之间调用的异常应该如何处理

    前言 在分布式服务的场景下 业务服务都将进行拆分 不同服务之间都会相互调用 如何做好异常处理是比较关键的 可以让业务人员在页面使用系统报错后 很清楚的看到服务报错的原因 而不是返回代码级别的异常报错 比如NullException Ille
  • 都是写代码,别人是IT精英,而你只配当程序“猿”?

    热点追踪 深度探讨 实地探访 商务合作 作为新一代信息技术的代表 区块链成为2020年政府工作报告的高频词汇 全国大多数省区市均重点提及到区块链 Part 1 产业区块链袭来 截至目前 在全国29个已召开两会的省 自治区 直辖市 中 区块链
  • javaScript基础面试题 ---this指向+原型的考题

    function Foo getName function console log 1 return this Foo getName function console log 2 Foo prototype getName functio
  • Linux开发

    目录 Linux开发工具 Linux编辑器 vim使用 1 vim的基本概念 2 vim的基本操作 3 vim正常模式命令集 4 vim末行模式命令集 Linux编译器 gcc g 使用 1 背景知识 2 gcc如何完成 Linux调试器
  • 把连续动态bmp转换为avi 分类: 文件格式 ...

    把动态bmp24转换为avi BYTE tmp buf 1024 768 4 生成avi void BMPtoAVI CString szAVIName CString strBmpDir CFileFind finder strBmpDi
  • 项目实训涉及的获取数据库数据,导出生成Excel表格(使用Nutz框架)

    前提要连接自己的数据库 java bean 就不写出来了 Service层 导出数据到Excel param ids return public boolean exportMeeting Integer ids List
  • matlab:sin函数

    可以发现sin pi 或者cos 1 2 pi 不等于0 初步推测应该是浮点运算的精度问题 由于sin cos tan等输入的参数为弧度制 而一般习惯角度制 所以解决的办法之一是用另外的函数 sind cosd tand等输入参数为角度制
  • Golang首字母大小写的意义(import package解析)

    1 大写相当于public 2 小写相当于private 注意 这个public和private是相对于包 go文件首行的package 后面跟的包名 来说的 3 1这个包名相对于它所处的实际的文件系统目录有什么关系呢 有关系 一般这个包名
  • Pycharm中文字体变成繁体解决方法

    文章目录 引言 原因分析 解决问题 引言 最近用pycharm的时候发现输入中文时字体突然变成繁体了 试了网上各种方式没有解决 最后发现是程序字体的问题 原因分析 因为是打代码 pycharm用的是英文字体 英文字体也可以打中文 但是一般会
  • 专升本——英语基础知识二

    八大成分 主语 谓语 宾语 定语 状语 补语 同位语 一 主语 动作的发起者 I love you I 是代词 代词做主语 The dog is cute The dog 是名词 名词做主语 Seven is my lucky Seven是
  • SimpleDateFormat时间不正确的问题

    开发遇到一个问题 new Date 获得的当前系统时间和经过SimpleDateFormat转换格式的时间不对应 相差一个小时 Date now new Date System out println now SimpleDateForma
  • Linux中将2块新增硬盘合并成一块,并挂载目录

    1 创建pv pvcreate dev sdb 硬盘1 pvcreate dev sdc 硬盘2 2 创建vg vgcreate 自定义LVM名称 硬盘 先使用硬盘1创建vg lvm data vgcreate lvm data dev s
  • RPM软件包管理与使用详解

    文章目录 1 概述 2 软件包命名规范 3 rpm包管理 3 1 rpm包安装 3 2 rpm包查询 3 3 rpm包升级 3 4 rpm包卸载 3 5 rpm包校验 3 6 rpm数据库重建 1 概述 什么是rpm包 rpm包是linux
  • 【VS

    1 CRT SECURE NO WARNINGS include
  • 小程序的 生命周期回调函数onLoad,onReady,onShow

    onLoad 只触发一次 页面加载时触发 从二级页面回来时不会触发 使用navigateBack 回跳是可以重新执行onLoad 以及tabBar首次会执行onload 第二次进入onload不会执行 可以传递参数 onShow 当小程序启
  • Jupyter Notebook的简单使用

    欢迎来到机器学习的世界 博客主页 卿云阁 欢迎关注 点赞 收藏 留言 本文由卿云阁原创 本阶段属于练气阶段 希望各位仙友顺利完成突破 首发时间 2021年3月3日 希望可以和大家一起完成进阶之路 作者水平很有限 如果发现错误 请留言轰炸哦
  • 虚拟机Ubuntu20.04 网络连接器图标开机不显示怎么办

    执行以下指令 sudo service network manager stop sudo rm var lib NetworkManager NetworkManager state sudo service network manage
  • Vue3的Teleport是什么?

    首先 Vue3的Teleport是一种魔法般的功能 它可以让你的组件瞬间移动到另一个位置 就像是现实生活中的瞬间传送器一样 但是它只适用于Vue3哦 你可能会想 这不是和Vue2的插槽差不多吗 NO NO NO 你可错了 Teleport和
  • JavaScript中的异步编程

    当我们在编写JavaScript代码时 经常会遇到需要执行长时间运行的任务的情况 例如从服务器获取数据或进行复杂的计算 在这些情况下 我们不希望阻塞用户界面 因为这会使网站看起来卡顿 甚至无响应 为了避免这种情况 我们需要使用JavaScr