请你谈谈:async与await是如何控制异步操作的执行顺序

news2024/9/26 1:17:11

async/await 是 JavaScript 中用于处理异步操作的一种语法糖,它使得异步代码的编写、阅读和维护变得更加容易和直观。asyncawait 关键字是在 ES2017(ES8)中引入的,旨在简化基于 Promise 的异步操作。

1 async

  • async 是一个函数声明的前缀,用于指定一个函数是异步的(promise.then等回调)。这意味着函数内部可能包含异步操作,如网络请求、文件读取等。
  • 当你将一个函数声明为 async 时,该函数会自动返回一个 Promise。如果函数正常结束(即没有显式返回 Promise 或其他值),它将返回一个解析为 undefined 的 Promise。如果函数通过 return 语句返回了一个值,那么返回的 Promise 将被解析为该值。如果函数内部抛出了异常,返回的 Promise 将被拒绝(rejected),异常值作为拒绝的原因。

当然可以,以下是分别举例说明这三种情况的代码:

1. 函数正常结束,没有显式返回 Promise 或其他值
async function asyncFunctionWithoutReturn() {
    // 函数体内执行一些操作,但不显式返回任何值
    console.log('函数执行了,但没有返回值');
    // 由于没有显式返回,所以函数将隐式返回一个解析为 undefined 的 Promise
}

let promise = asyncFunctionWithoutReturn()
promise.then(result => {
    console.log(result); // 输出:undefined
}).catch(error => {
    console.error(error); // 这里不会被调用,因为没有抛出异常
});

2. 函数通过 return 语句返回了一个值
async function asyncFunctionWithReturnValue() {
    // 函数体内执行一些操作,并通过 return 语句返回一个值
    console.log('函数执行了,并返回了一个值');
    return 'Hello, async!';
    // 由于有显式返回,所以函数将返回一个解析为 'Hello, async!' 的 Promise
}

let promise = asyncFunctionWithReturnValue()
promise.then(result => {
    console.log(result); // 输出:Hello, async!
}).catch(error => {
    console.error(error); // 这里不会被调用,因为没有抛出异常
});

3. 函数内部抛出了异常
async function asyncFunctionThrowsError() {
    // 函数体内执行一些操作,并抛出一个异常
    console.log('函数执行中...');
    throw new Error('出错了!');
    // 由于抛出了异常,所以函数将返回一个被拒绝的 Promise,异常值作为拒绝的原因
}
let promise = asyncFunctionThrowsError()
promise.then(result => {
    // 这里不会被调用,因为 Promise 被拒绝了
    console.log(result);
}).catch(error => {
    console.error(error.message); // 输出:Error: 出错了!
    // 捕获到异常,并可以在这里处理它
});

在这三个例子中,我们分别展示了当一个函数被声明为 async 时,它如何根据函数体内的不同情况自动返回一个 Promise。第一个例子展示了没有显式返回任何值时的情况,第二个例子展示了通过 return 语句返回一个值的情况,第三个例子展示了函数内部抛出异常时的情况。这些例子清楚地说明了 async 函数如何处理其返回值和异常。

2 await

await 关键字是 JavaScript 中处理异步操作的一个非常强大的工具,但它确实有一些限制和使用场景:

  1. 只能在 async 函数内部使用await 只能在被 async 关键字声明的函数或方法内部使用。这意味着你不能在普通的同步函数或全局作用域中使用 await

  2. 等待 Promise 完成await 会暂停 async 函数的执行,直到它等待的 Promise 被解决(fulfilled)或拒绝(rejected)。这使得你可以以类似于同步代码的方式来编写异步逻辑。

  3. 返回 Promise 解决的结果:当 await 等待的 Promise 被解决时,await 表达式会返回 Promise 解决的值。这个值可以被赋给变量,或者用于进一步的计算。

  4. 异常处理:如果 await 等待的 Promise 被拒绝,那么 await 表达式会抛出一个异常。这个异常可以被 async 函数内部的 try...catch 语句捕获,就像处理同步代码中的异常一样。

  5. 提升代码可读性:使用 async/await 可以使异步代码更加清晰和易于理解,因为它允许你以更接近同步代码的方式来编写和执行异步逻辑。

  6. 不阻塞主线程:尽管 await 会暂停 async 函数的执行,但它不会阻塞整个 JavaScript 运行时或主线程。JavaScript 运行时可以继续执行其他任务,如事件处理、定时器回调等,直到等待的 Promise 完成。

在 JavaScript 中,await 关键字用于等待一个 Promise 完成,并且它只能在 async 函数内部使用。await 的行为取决于它右侧的表达式:

  1. 如果表达式是 Promise 对象

    • await 会暂停 async 函数的执行,直到该 Promise 被解决(fulfilled)或拒绝(rejected)。
    • 如果 Promise 被成功解决,await 会返回解决的值。
      在这里插入图片描述 - 如果 Promise 被拒绝,await 会抛出一个异常,这个异常可以通过 try...catch 结构来捕获和处理。在这里插入图片描述
  2. 如果表达式不是 Promise 对象

    • await 会立即返回该表达式的值,而不会等待任何异步操作完成。这是因为非 Promise 类型的值被视为已经解决的 Promise(即其值已经可用)。

3 async与await结合实践

当然,下面是一个典型的回调地狱(Callback Hell)的例子,这个例子通常出现在处理多个异步操作并且每个操作的结果都是下一个操作所需的输入时。我们将使用Node.js的fs模块来模拟文件读取操作,尽管在Node.js v10及更高版本中,推荐使用fs.promises API或util.promisify来避免回调地狱。

回调地狱的例子

假设我们需要按顺序读取三个文件,并将它们的内容拼接起来。使用传统的回调方式,代码可能会像这样:

const fs = require('fs');

fs.readFile('file1.txt', 'utf8', (err, data1) => {
    if (err) throw err;
    fs.readFile('file2.txt', 'utf8', (err, data2) => {
        if (err) throw err;
        fs.readFile('file3.txt', 'utf8', (err, data3) => {
            if (err) throw err;
            console.log(data1 + data2 + data3);
        });
    });
});

为了解决这个问题,我们可以使用async/awaitfs.promises API(或在较旧版本的Node.js中使用util.promisify转换的fs.readFile)。下面是使用fs.promises API的示例:

const fs = require('fs').promises;

async function readFileConcatenate() {
    try {
        const data1 = await fs.readFile('file1.txt', 'utf8');
        const data2 = await fs.readFile('file2.txt', 'utf8');
        const data3 = await fs.readFile('file3.txt', 'utf8');

        console.log(data1 + data2 + data3);
    } catch (error) {
        console.error('Error reading file:', error);
    }
}

// 调用函数
readFileConcatenate();

在这个async函数中,我们使用了await来等待每个fs.readFile调用的结果。由于await只能在async函数内部使用,因此我们将文件读取逻辑封装在了一个名为readFileConcatenateasync函数中。这种方式使得代码更加清晰和易于维护,同时避免了回调地狱的问题。

如果你正在使用Node.js的较旧版本,并且fs模块没有内置的promises API,你可以使用util.promisify来转换fs.readFile

const fs = require('fs');
const util = require('util');

// 转换fs.readFile为返回Promise的函数
const readFile = util.promisify(fs.readFile);

async function readFileConcatenate() {
    try {
        const data1 = await readFile('file1.txt', 'utf8');
        const data2 = await readFile('file2.txt', 'utf8');
        const data3 = await readFile('file3.txt', 'utf8');

        console.log(data1 + data2 + data3);
    } catch (error) {
        console.error('Error reading file:', error);
    }
}

// 调用函数
readFileConcatenate();

这种方式同样有效,并且可以在不支持fs.promises API的Node.js版本中使用。

要使用asyncawait来确保fun1fun2fun3这三个方法按顺序调用,并且每个方法内部都执行一个异步的AJAX请求,你可以首先确保这三个方法都返回Promise。然后,在另一个方法中,你可以使用await来等待每个方法完成后再继续执行下一个。

以下是一个简单的示例,展示了如何实现这一点:

// 假设我们使用fetch API来模拟AJAX请求(你也可以使用XMLHttpRequest或其他库)

// fun1 方法,返回一个Promise
function fun1() {
    return new Promise((resolve, reject) => {
        // 模拟异步请求
        setTimeout(() => {
            console.log('fun1 执行完毕');
            resolve('fun1的结果');
        }, 1000); // 假设请求耗时1秒
    });
}

// fun2 方法,同样返回一个Promise
function fun2() {
    return new Promise((resolve, reject) => {
        // 模拟异步请求
        setTimeout(() => {
            console.log('fun2 执行完毕');
            resolve('fun2的结果');
        }, 1000); // 假设请求耗时1秒
    });
}

// fun3 方法,也返回一个Promise
function fun3() {
    return new Promise((resolve, reject) => {
        // 模拟异步请求
        setTimeout(() => {
            console.log('fun3 执行完毕');
            resolve('fun3的结果');
        }, 1000); // 假设请求耗时1秒
    });
}

// 调用这三个方法的函数,使用async和await来确保顺序执行
async function executeFunctionsInOrder() {
    try {
        const result1 = await fun1(); // 等待fun1完成
        console.log('fun1的返回结果:', result1);

        const result2 = await fun2(); // 等待fun2完成
        console.log('fun2的返回结果:', result2);

        const result3 = await fun3(); // 等待fun3完成
        console.log('fun3的返回结果:', result3);
    } catch (error) {
        // 如果有任何一个函数出错,这里会捕获到错误
        console.error('执行过程中发生错误:', error);
    }
}

// 调用函数
executeFunctionsInOrder();

在这个例子中,fun1fun2fun3都使用了setTimeout来模拟异步操作(例如AJAX请求)。每个函数都返回一个Promise,该Promise在异步操作完成后被解决(resolve)。在executeFunctionsInOrder函数中,我们使用了async关键字来标记该函数为异步函数,这样我们就可以在函数体内使用await来等待每个异步操作的完成。注意,await只能用在async函数内部。

运行这段代码,你会看到控制台按顺序输出了fun1fun2fun3的执行结果,每个之间大约间隔1秒(由setTimeout设置)。

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

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

相关文章

Pytorch如何指定device(cuda or cpu)例子解析

代码示例: 在PyTorch中,指定设备(CPU或CUDA)是一个非常重要的步骤,特别是当你在进行深度学习训练时。以下是一些指定设备的详细例子: 检查CUDA是否可用: 首先,你需要检查你的机器是否支持CUDA&…

【C++ Primer Plus习题】5.9

问题: 解答: #include <iostream> #include <cstring> using namespace std;#define SIZE 20int main() {string words[SIZE];string done "done";int count 0;while (true){cout << "请输入单词:" << endl;cin >> words…

2054. 骑马修栅栏

代码 #include<bits/stdc.h> using namespace std; int mp[505][505]; queue<int> ans; int du[505]; int n0,m,u,v;void dfs(int i) {for(int j1;j<n;j){if(mp[i][j]>1){mp[i][j]--;mp[j][i]--;dfs(j);}}ans.push(i); } int main() {cin>>m;for(int …

javaSpringBootmysql的大学生心理健康管理系统39182-计算机毕业设计项目选题推荐(附源码)

摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;高校当然也不例外。大学生心理健康管理系统是以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#xff0c…

一文搞懂不确定性原理

在讲这个之前&#xff0c;我们先要搞清楚&#xff0c;什么是不确定性原理&#xff1f;然后再解释它为什么就是不确定的呢&#xff1f; 我还模糊记得我第一次接触这个东西的时候&#xff0c;是在高中物理教材上面提了一下。其中印象最深的就是&#xff1a;动量确定&#xff0c;…

记录|Steam登录不上,打开速度慢等问题

目录 前言一、方法1二、方法2&#xff1a;cmd指令三、steam账号可以多台电脑一起用吗&#xff1f;更新时间 前言 参考视频&#xff1a; Steam登不上&#xff1f;商店打不开&#xff1f;多种方案助你解决问题&#xff01; 一、方法1 打开Steam的快捷方式的“属性”&#xff0c;…

[ICLR-24] LRM: Large Reconstruction Model for Single Image to 3D

[pdf | proj | code] 本文首次提出大型重建模型&#xff08;Large Reconstruction Model, LRM&#xff09;&#xff0c;实现5s内对单图物体的3D重建。在128张A100&#xff08;40G&#xff09;上训练30 epochs。 LRM包含三个部分&#xff0c;具体框架如下&#xff1a; 图片编码…

[C++] 初识 智能指针

标题&#xff1a;[C] 初识 智能指针 水墨不写bug 目录 一、前言 二、智能指针 1. 什么是RAII&#xff1f; 2.智能指针分类 三、智能指针简介 1.std::auto_ptr 2.std::unique_ptr 3.std::shared_ptr 正文开始&#xff1a; 一、前言 C智能指针的出现是有一定的背景的&am…

shell程序设计入门(三)

shell程序设计入门&#xff08;三&#xff09; 导语命令简单命令break:命令continueechoevalexecexitexprprintfreturnshift 复杂指令.exportsetunsettrapfindgrep 总结参考文献 导语 本篇介绍一些shell中常用的复杂命令及其使用&#xff0c;如set、echo、expr等命令 命令 简…

【每日一题】【区间合并】【贪心 模拟】多米诺骨牌 牛客小白月赛99 E题 C++

牛客小白月赛99 E题 多米诺骨牌 题目背景 牛客小白月赛99 题目描述 样例 #1 样例输入 #1 3 6 1 1 1 1 3 2 1 4 3 2 7 9 11 6 2 1 1 1 3 2 1 4 3 2 7 9 11 5 4 1 4 1 1 2 1 2 3 6 8样例输出 #1 3 6 5做题思路 按照玩多米诺骨牌的方式。 先将多米诺骨牌按照骨牌位置从小…

ai伴学之“修图”

偶一张孩子专注的抓拍&#xff0c;通过与ai探讨修图心得让做图理念更完备。 (笔记模板由python脚本于2024年08月25日 18:23:49创建&#xff0c;本篇笔记适合喜欢搞图的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a…

JAVA_10

JAVA_10 JAVA异常机制及bug追踪1. 异常 JAVA异常机制及bug追踪 1. 异常 英文:Exception 所谓异常处理&#xff0c;就是指程序在出现问题时依然可以正确的执行完。Java面向对象处理异常过程 抛出异常:在执行一个方法时&#xff0c;如果发生异常&#xff0c;则这个方法生成代表…

Layer-refined Graph Convolutional Networks for Recommendation【ICDE2023】

Layer-refined Graph Convolutional Networks for Recommendation 论文&#xff1a;https://arxiv.org/abs/2207.11088 源码&#xff1a;https://github.com/enoche/MMRec/blob/master/README.md 摘要 基于图卷积网络&#xff08;GCN&#xff09;的抽象推荐模型综合了用户-项目…

Chainlit接入FastGpt接口完美对接,实现全新的用户聊天界面

前言 由于fastgpt只提供了一个分享用的网页应用&#xff0c;网页访问地址没法自定义&#xff0c;虽然可以接入NextWeb/ChatGPT web等开源应用。但是如果我们想直接给客户应用&#xff0c;还需要客户去设置配置&#xff0c;里面还有很多我们不想展示给客户的东西怎么办&#xf…

# 利刃出鞘_Tomcat 核心原理解析(九)-- Tomcat 安全

利刃出鞘_Tomcat 核心原理解析&#xff08;九&#xff09;-- Tomcat 安全 一、Tomcat专题 - Tomcat安全 - 配置安全 1、 删除 tomcat 的 webapps 目录下的所有文件&#xff0c;禁用 tomcat 管理界面. 如下目录均可删除&#xff1a; D:\java-test\apache-tomcat-8.5.42-wind…

轻松实现PDF转图片!2024四大实用工具推荐!

有时候我们需要将PDF文件中的内容转换为图片格式&#xff0c;以便在不同的平台和设备上更好地展示和分享。"PDF转图片"这一需求催生了众多转换工具的出现&#xff0c;它们以高效、便捷的服务帮助用户轻松实现格式转换。 福昕PDF转换大师&#xff08;365客户端&#…

JAVA Future类详解

在编程中&#xff0c;Java中的"Future"是一个接口&#xff0c;代表是作为主线程开辟的一个分支任务&#xff0c;处理耗时的业务&#xff0c;并且可以可以为主线程最终返回异步计算的结果。此外&#xff0c;它提供了检查计算是否完成&#xff0c;等待其完成&#xff0…

ISP 3A 算法:自动曝光(AE)中的平均亮度法详解

在自动曝光&#xff08;AE&#xff09;算法中&#xff0c;平均亮度法是一种经典且广泛应用的技术。它通过计算场景中所有像素的平均亮度来确定最佳曝光设置&#xff0c;从而保证图像的整体亮度处于适当的水平。尽管该方法相对简单&#xff0c;但它在AE算法中扮演着重要的角色&a…

仕考网:专科考公好考吗?有岗位吗?

2024年&#xff0c;国家公务员以及大多数省市的公务员考试接受至少拥有大专学历的考生。某些特定职位&#xff0c;例如上海市和北京市的岗位&#xff0c;可能要求考生必须持有本科或以上学历才能参与考试。 属于国家公务员考试、省直属单位、市直属单位以及中央直属单位的职位…

奥斯卡影后斯特里普和马丁肖特在最近的这次约会后再次引发热议

奥斯卡影后斯特里普和马丁肖特在最近的这次约会后再次引发热议 2024-08-24 00:00 发布于&#xff1a;河北省 自从梅丽尔斯特里普于 2023 年与相恋多年的丈夫分手以来&#xff0c;媒体对她的关注度只增不减。毕竟&#xff0c;这是好莱坞最著名的女演员 40 多年来第一次单身&…