当前位置:网站首页>Promise的 简单使用
Promise的 简单使用
2022-08-03 16:43:00 【华为云】
Promise 是一个对象,它代表了一个异步操作的最终完成或者失败。因为大多数人仅仅是使用已创建的 Promise 实例对象,所以本教程主要分两部分:
怎样使用 Promise
如何创建 Promise
本质上 Promise 是一个函数返回的对象,我们可以在它上面绑定回调函数,这样我们就不需要在一开始把回调函数作为参数传入这个函数了。
假设现在有一个名为 createAudioFileAsync() 的函数,它接收一些配置和两个回调函数,然后异步地生成音频文件。一个回调函数在文件成功创建时被调用,另一个则在出现异常时被调用。
以下为使用 createAudioFileAsync() 的示例:
// 成功的回调函数function successCallback(result) { console.log("音频文件创建成功: " + result);}// 失败的回调函数function failureCallback(error) { console.log("音频文件创建失败: " + error);}createAudioFileAsync(audioSettings, successCallback, failureCallback)更现代的函数会返回一个 Promise 对象,使得你可以将你的回调函数绑定在该 Promise 上。
如果函数 createAudioFileAsync() 被重写为返回 Promise 的形式,那么我们可以像下面这样简单地调用它:
const promise = createAudioFileAsync(audioSettings);promise.then(successCallback, failureCallback);或者简写为:
createAudioFileAsync(audioSettings).then(successCallback, failureCallback);我们把这个称为 异步函数调用,这种形式有若干优点,下面我们将会逐一讨论。
约定
不同于“老式”的传入回调,在使用 Promise 时,会有以下约定:
在本轮 事件循环 运行完成之前,回调函数是不会被调用的。
即使异步操作已经完成(成功或失败),在这之后通过
then()添加的回调函数也会被调用。通过多次调用
then()可以添加多个回调函数,它们会按照插入顺序进行执行。
Promise 很棒的一点就是链式调用(chaining)。
链式调用
连续执行两个或者多个异步操作是一个常见的需求,在上一个操作执行成功之后,开始下一个的操作,并带着上一步操作所返回的结果。我们可以通过创造一个 Promise 链来实现这种需求。
见证奇迹的时刻:then() 函数会返回一个和原来不同的新的 Promise:
const promise = doSomething();const promise2 = promise.then(successCallback, failureCallback);或者
const promise2 = doSomething().then(successCallback, failureCallback);promise2 不仅表示 doSomething() 函数的完成,也代表了你传入的 successCallback 或者 failureCallback 的完成,这两个函数也可以返回一个 Promise 对象,从而形成另一个异步操作,这样的话,在 promise2 上新增的回调函数会排在这个 Promise 对象的后面。
基本上,每一个 Promise 都代表了链中另一个异步过程的完成。
在过去,要想做多重的异步操作,会导致经典的回调地狱:
doSomething(function(result) { doSomethingElse(result, function(newResult) { doThirdThing(newResult, function(finalResult) { console.log('Got the final result: ' + finalResult); }, failureCallback); }, failureCallback);}, failureCallback);现在,我们可以把回调绑定到返回的 Promise 上,形成一个 Promise 链:
doSomething().then(function(result) { return doSomethingElse(result);}).then(function(newResult) { return doThirdThing(newResult);}).then(function(finalResult) { console.log('Got the final result: ' + finalResult);}).catch(failureCallback);then 里的参数是可选的,catch(failureCallback) 是 then(null, failureCallback) 的缩略形式。如下所示,我们也可以用箭头函数来表示:
doSomething().then(result => doSomethingElse(result)).then(newResult => doThirdThing(newResult)).then(finalResult => { console.log(`Got the final result: ${finalResult}`);}).catch(failureCallback);注意:一定要有返回值,否则,callback 将无法获取上一个 Promise 的结果。(如果使用箭头函数,() => x 比 () => { return x; } 更简洁一些,但后一种保留 return 的写法才支持使用多个语句。)。
Catch 的后续链式操作
有可能会在一个回调失败之后继续使用链式操作,即,使用一个 catch,这对于在链式操作中抛出一个失败之后,再次进行新的操作会很有用。请阅读下面的例子:
new Promise((resolve, reject) => { console.log('初始化'); resolve();}).then(() => { throw new Error('有哪里不对了'); console.log('执行「这个」”');}).catch(() => { console.log('执行「那个」');}).then(() => { console.log('执行「这个」,无论前面发生了什么');});输出结果如下:
初始化执行“那个”执行“这个”,无论前面发生了什么注意:因为抛出了错误 有哪里不对了,所以前一个 执行「这个」 没有被输出。
错误传递
在之前的回调地狱示例中,你可能记得有 3 次 failureCallback 的调用,而在 Promise 链中只有尾部的一次调用。
doSomething().then(result => doSomethingElse(result)).then(newResult => doThirdThing(newResult)).then(finalResult => console.log(`Got the final result: ${finalResult}`)).catch(failureCallback);通常,一遇到异常抛出,浏览器就会顺着 Promise 链寻找下一个 onRejected 失败回调函数或者由 .catch() 指定的回调函数。这和以下同步代码的工作原理(执行过程)非常相似。
try { let result = syncDoSomething(); let newResult = syncDoSomethingElse(result); let finalResult = syncDoThirdThing(newResult); console.log(`Got the final result: ${finalResult}`);} catch(error) { failureCallback(error);}在 ECMAScript 2017 标准的 async/await 语法糖中,这种异步代码的对称性得到了极致的体现:
async function foo() { try { const result = await doSomething(); const newResult = await doSomethingElse(result); const finalResult = await doThirdThing(newResult); console.log(`Got the final result: ${finalResult}`); } catch(error) { failureCallback(error); }}这个例子是在 Promise 的基础上构建的,例如,doSomething() 与之前的函数是相同的。
边栏推荐
- 产品-Axure9英文版,轮播图效果
- C专家编程 第3章 分析C语言的声明 3.9 轻松一下---驱动物理实体的软件
- uniapp的webview滑动缩放
- Kubernetes 笔记 / 入门 / 生产环境 / 容器运行时
- Web3的开源为何会如此受到人们喜爱?
- B站回应HR称核心用户是Loser;微博回应宕机原因;Go 1.19 正式发布|极客头条
- LeetCode·72.编辑距离·动态规划
- C专家编程 第3章 分析C语言的声明 3.7 typedef struct foo{... foo;}的含义
- php之相似文章标题similar_text()函数使用
- After using Stream for many years, does collect still have these "saucy operations"?
猜你喜欢

SQL中对 datetime 类型操作

deepstresam的插件配置说明,通过配置osd,设置字体的背景为透明

【带你了解SDN和网络虚拟化】

面试不再被吊打!这才是Redis分布式锁的七种方案的正确打开方式

MySQL相关介绍

#夏日挑战赛# HarmonyOS 实现一个绘画板

B站回应HR称核心用户是Loser;微博回应宕机原因;Go 1.19 正式发布|极客头条

学会 Arthas,让你 3 年经验掌握 5 年功力!

Web3 安全风险令人生畏?应该如何应对?

After using Stream for many years, does collect still have these "saucy operations"?
随机推荐
Description of the functional scenario of "collective storage and general governance" in the data center
C专家编程 第3章 分析C语言的声明 3.6 typedef int x[10]和#define x int[10]的区别
面试突击71:GET 和 POST 有什么区别?
微信小程序 - 数组 push / unshift 追加后数组返回内容为数字(数组添加后打印结果为 Number 数值类型)
高效的组织信息共享知识库是一种宝贵的资源
【翻译】关于扩容一个百万级别用户系统的六个课程
C语言03、数组
如何在 DataWorks 中 写SQL语句监控数据的变化到达一定的值 进行提示
掌握Redis的Sentinel哨兵原理,可助你拿到25k的offer
Async的线程池使用的哪个?
C语言02、语句、函数
Component communication - parent-child component communication
浅谈Service Mesh对业务系统的价值
Detailed explanation of setting HiSilicon MMZ memory and OS memory
Kubernetes 笔记 / 目录
软考 --- 软件工程(1)概念、开发模型
超分重建数据集
EasyExcel实现动态列解析和存表
20. Valid Parentheses
php之相似文章标题similar_text()函数使用