0

0

JavaScript 中的 Promise:理解、处理和掌握异步代码

WBOY

WBOY

发布时间:2024-09-03 19:03:31

|

529人浏览过

|

来源于dev.to

转载

javascript 中的 promise:理解、处理和掌握异步代码

简介

我曾经是一名 java 开发人员,我记得第一次接触 javascript 中的 promise 时。尽管这个概念看起来很简单,但我仍然无法完全理解 promise 是如何工作的。当我开始在项目中使用它们并了解它们解决的案例时,情况发生了变化。然后灵光乍现的时刻到来了,一切都变得更加清晰了。随着时间的推移,promise 成为我工具带上的宝贵武器。当我可以在工作中使用它们并解决函数之间的异步处理时,这是一种奇怪的满足感。

您可能首先在从 api 获取数据时遇到 promise,这也是最常见的示例。最近,我接受了采访,猜猜第一个问题是什么“你能告诉我 promise 和 async await 之间的区别吗?”。我对此表示欢迎,因为我认为这是一个很好的起点,可以更好地了解申请人如何理解这些机制的运作方式。然而,他或她主要使用其他库和框架。它让我记下差异并描述处理异步函数错误的良好实践。

承诺是什么

让我们从最初的问题开始:“promise 是什么?” promise 是我们还不知道的值的占位符,但我们将通过异步计算/函数得到它。如果承诺顺利的话,我们就会得到结果。如果 promise 进展不顺利,那么 promise 将返回错误。

promise 的基本示例

定义一个承诺

通过调用 promise 的构造函数并传递两个回调函数来定义 promise:resolvereject.

const newpromise = new promise((resolve, reject) => {
    resolve('hello');
    // reject('error');
});

当我们想要成功解析 promise 时,我们调用解析函数。拒绝是在评估我们的逻辑过程中发生错误时拒绝承诺。

立即学习Java免费学习笔记(深入)”;

检索 promise 结果

我们使用内置函数 then 来获取 promise 的结果。它有两个传递的回调,结果和错误。当函数resolve成功解析promise时,将调用结果。如果 promise 未解决,则会调用第二个函数错误。该函数由拒绝或抛出的另一个错误触发。

newpromise.then(result => {
    console.log(result); // hello
}, error => {
    console.log("there shouldn't be an error");
});

在我们的示例中,我们将得到结果 hello,因为我们成功解决了 promise。

承诺的错误处理

当 promise 被拒绝时,总是会调用它的第二个错误回调。

const newpromise1 = new promise((resolve, reject) => {
  reject('an error occurred in promise1');
});

newpromise1.then(
  (result) => {
    console.log(result); // it is not invoked
  },
  (error) => {
    console.log(error); // 'an error occurred in promise1'
  }
);

为了清晰起见,更推荐的方法是使用内置的 catch 方法。

const newpromise2 = new promise((resolve, reject) => {
  reject('an error occurred in promise2');
});

newpromise2
  .then((result) => {
    console.log(result); // it is not invoked
  })
  .catch((error) => {
    console.log(error); // 'an error occurred in promise2'
  });

catch 方法是链式的,并提供了自己的错误回调。当 promise 被拒绝时它会被调用。

两个版本都运行良好,但链接在我看来更具可读性,并且在使用我们进一步介绍的其他内置方法时非常方便。

连锁承诺

一个承诺的结果可能是另一个承诺。在这种情况下,我们可以链接任意数量的 then 函数。

getjson('categories.json')
    .then(categories => {
        console.log('fetched categories:', categories);

        return getjson(categories[0].itemsurl);
    })
    .then(items => {
        console.log('fetched items:', items);

        return getjson(items[0].detailsurl);
    })
    .then(details => {
        console.log('fetched details:', details);
    })
    .catch(error => {
        console.error('an error has occurred:', error.message);
    });

在我们的示例中,它用于缩小搜索结果范围以获取详细数据。每个 then 函数也可以有其错误回调。如果我们只关心捕获调用链中的任何错误,那么我们可以利用 catch 函数。如果任何 promise 返回错误,它将被评估。

答应一切

有时我们想等待更独立的 promise 的结果,然后根据结果采取行动。如果我们不关心 promise 的解析顺序,我们可以使用内置函数 promise.all。

promise.all([
    getjson('categories.json'),
    getjson('technology_items.json'),
    getjson('science_items.json')
])
    .then(results => {
        const categories = results[0];
        const techitems = results[1];
        const scienceitems = results[2];

        console.log('fetched categories:', categories);
        console.log('fetched technology items:', techitems);
        console.log('fetched science items:', scienceitems);

        // fetch details of the first item in each category
        return promise.all([
            getjson(techitems[0].detailsurl),
            getjson(scienceitems[0].detailsurl)
        ]);
    })
    .then(detailsresults => {
        const laptopdetails = detailsresults[0];
        const physicsdetails = detailsresults[1];

        console.log('fetched laptop details:', laptopdetails);
        console.log('fetched physics details:', physicsdetails);
    })
    .catch(error => {
        console.error('an error has occurred:', error.message);
    });

promise.all 接受 promise 数组并返回结果数组。如果 promise 之一被拒绝,则 promise.all 也会被拒绝。

赛车承诺

另一个内置功能是 promise.race。当您有多个异步函数(promise)并且您想要对它们进行竞赛时,可以使用它。

promise.race([
    getjson('technology_items.json'),
    getjson('science_items.json')
])
    .then(result => {
        console.log('first resolved data:', result);
    })
    .catch(error => {
        console.error('an error has occurred:', error.message);
    });

promise 的执行可能需要不同的时间,promise.race 会评估数组中第一个已解决或拒绝的 promise。当我们不关心顺序但我们想要最快的异步调用的结果时使用它。

讯飞公文
讯飞公文

讯飞公文写作助手是一款依托于讯飞星火大模型、专为广大公文材料撰稿人打造的高效公文写作平台。

下载

什么是异步等待

如您所见,编写 promise 需要大量样板代码。幸运的是,我们有原生的 async await 功能,这使得使用 promises 变得更加容易。我们用“async”这个词来标记一个函数,并且通过它,我们说在代码中的某个地方我们将调用异步函数,我们不应该等待它。然后使用await 字调用异步函数。

异步等待的基本示例

const fetchdata = async () => {
    try {
        // fetch the categories
        const categories = await getjson('categories.json');
        console.log('fetched categories:', categories);

        // fetch items from the first category (technology)
        const techitems = await getjson(categories[0].itemsurl);
        console.log('fetched technology items:', techitems);

        // fetch details of the first item in technology (laptops)
        const laptopdetails = await getjson(techitems[0].detailsurl);
        console.log('fetched laptop details:', laptopdetails);
    } catch (error) {
        console.error('an error has occurred:', error.message);
    }
};

fetchdata();

我们的 fetchdata 被标记为异步,它允许我们使用await 来处理函数内的异步调用。我们调用更多的 promise,它们会一个接一个地进行评估。

如果我们想处理错误,我们可以使用 try...catch 块。然后被拒绝的错误被捕获在 catch 块中,我们可以像记录错误一样对其采取行动。

有什么不同

它们都是 javascript 处理异步代码的功能。主要区别在于 promise 使用 then 和 catch 链接时的语法,但 async wait 语法更多地采用同步方式。它使它更容易阅读。当异步等待利用 try...catch 块时,错误处理更加简单。这是面试时很容易被问到的问题。在回答过程中,您可以更深入地了解两者的描述并突出显示这些差异。

承诺功能

当然,您可以通过 async wait 使用所有功能。例如 promise.all。

const fetchalldata = async () => {
    try {
        // use await with promise.all to fetch multiple json files in parallel
        const [techitems, scienceitems, laptopdetails] = await promise.all([
            getjson('technology_items.json'),
            getjson('science_items.json'),
            getjson('laptops_details.json')
        ]);

        console.log('fetched technology items:', techitems);
        console.log('fetched science items:', scienceitems);
        console.log('fetched laptop details:', laptopdetails);
    } catch (error) {
        console.error('an error occurred:', error.message);
    }
};

实际用例

promise 是 javascript 中用于处理异步代码的基本功能。主要使用方法如下:

从 api 获取数据

如上面的示例所示,这是 promise 最常用的用例之一,您每天都会使用它。

处理文件操作

可以使用 promise 来异步读写文件,特别是通过 node.js 模块 fs.promises

import * as fs from 'fs/promises';

const writeFileAsync = async (filePath, content, options = {}) => {
    try {
        await fs.writeFile(filePath, content, options);
        console.log(`File successfully written to ${filePath}`);
    } catch (error) {
        console.error(`Error writing file to ${filePath}:`, error.message);
    }
};

const filePath = 'output.txt';
const fileContent = 'Hello, this is some content to write to the file!';
const fileOptions = { encoding: 'utf8', flag: 'w' }; // Optional file write options

writeFileAsync(filePath, fileContent, fileOptions);

基于 promise 的库

axios 是你应该熟悉的库。 axios 在客户端处理 http 请求,使用广泛。

express 是 node.js 的 web 框架。它使构建 web 应用程序和 api 变得容易,并且当您将 promise 与 express 结合使用时,您的代码将保持干净且易于管理。

带有示例的存储库

所有示例都可以在:https://github.com/princam/promise-example

概括

promise 是 javascript 的基本组成部分,对于处理 web 开发中的异步任务至关重要。无论是获取数据、处理文件还是使用 axios 和 express 等流行库,您都会经常在代码中使用 promise。

在本文中,我们探讨了 promise 是什么、如何定义和检索其结果以及如何有效地处理错误。我们还介绍了链接、promise.all 和 promise.race 等关键功能。最后,我们引入了 async wait 语法,它提供了一种更直接的方式来使用 promise。

理解这些概念对于任何 javascript 开发人员来说都至关重要,因为它们是您日常依赖的工具。

如果您还没有尝试过,我建议您编写一个简单的代码片段来从 api 获取数据。您可以从一个有趣的 api 开始进行试验。另外,此存储库中提供了所有示例和代码片段供您探索。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

520

2023.06.20

js获取当前时间
js获取当前时间

JS全称JavaScript,是一种具有函数优先的轻量级,解释型或即时编译型的编程语言;它是一种属于网络的高级脚本语言,主要用于Web,常用来为网页添加各式各样的动态功能。js怎么获取当前时间呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

348

2023.07.28

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

464

2023.08.03

js是什么意思
js是什么意思

JS是JavaScript的缩写,它是一种广泛应用于网页开发的脚本语言。JavaScript是一种解释性的、基于对象和事件驱动的编程语言,通常用于为网页增加交互性和动态性。它可以在网页上实现复杂的功能和效果,如表单验证、页面元素操作、动画效果、数据交互等。

5512

2023.08.17

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

485

2023.09.01

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

213

2023.09.04

Js中concat和push的区别
Js中concat和push的区别

Js中concat和push的区别:1、concat用于将两个或多个数组合并成一个新数组,并返回这个新数组,而push用于向数组的末尾添加一个或多个元素,并返回修改后的数组的新长度;2、concat不会修改原始数组,是创建新的数组,而push会修改原数组,将新元素添加到原数组的末尾等等。本专题为大家提供concat和push相关的文章、下载、课程内容,供大家免费下载体验。

239

2023.09.14

js截取字符串的方法介绍
js截取字符串的方法介绍

JavaScript字符串截取方法,包括substring、slice、substr、charAt和split方法。这些方法可以根据具体需求,灵活地截取字符串的不同部分。在实际开发中,根据具体情况选择合适的方法进行字符串截取,能够提高代码的效率和可读性 。

273

2023.09.21

Golang处理数据库错误教程合集
Golang处理数据库错误教程合集

本专题整合了Golang数据库错误处理方法、技巧、管理策略相关内容,阅读专题下面的文章了解更多详细内容。

132

2026.02.06

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Git 教程
Git 教程

共21课时 | 3.5万人学习

Git版本控制工具
Git版本控制工具

共8课时 | 1.5万人学习

Git中文开发手册
Git中文开发手册

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号