当前位置:网站首页>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() 与之前的函数是相同的。
边栏推荐
- 【系统学习编程-编程入门-全民编程 视频教程】
- error:Illegal instruction (core dumped),离线下载安装这个other版本numpy
- C语言02、语句、函数
- C专家编程 第2章 这不是Bug,而是语言特性 2.1 这关语言特性何事,在Fortran里这就是Bug呀
- C专家编程 第3章 分析C语言的声明 3.8 理解所有分析过程的代码段
- 从MatePad Pro进化看鸿蒙OS的生态势能
- SQL中对 datetime 类型操作
- 学会 Arthas,让你 3 年经验掌握 5 年功力!
- C专家编程 第3章 分析C语言的声明 3.5 typedef可以成为你的朋友
- 面试突击:什么是粘包和半包?怎么解决?
猜你喜欢
随机推荐
数字资产的价值激发:NFT 质押
C专家编程 第2章 这不是Bug,而是语言特性 2.1 这关语言特性何事,在Fortran里这就是Bug呀
正向代理与反向代理
[Deep Learning] Today's bug (August 2)
[Unity Getting Started Plan] Basic Concepts (7) - Input Manager & Input Class
How to write SQL statements in DataWorks monitoring data reaches a certain value to indicate the change of
LeetCode·899.有序队列·最小表示法
Looking at the ecological potential of Hongmeng OS from the evolution of MatePad Pro
After using Stream for many years, does collect still have these "saucy operations"?
Web3 安全风险令人生畏?应该如何应对?
Selective Search学习笔记
机器人开发--Universal Scene Description(USD)
deepstresam的插件配置说明,通过配置osd,设置字体的背景为透明
C专家编程 第3章 分析C语言的声明 3.6 typedef int x[10]和#define x int[10]的区别
工程仪器设备在线监测管理系统常见问题和注意事项
“68道 Redis+168道 MySQL”精品面试题(带解析),你背废了吗?
面试突击:什么是粘包和半包?怎么解决?
阿里二面:没有 accept,能建立 TCP 连接吗?
Windows 事件转发到 SQL 数据库
Huawei, Lenovo, BAIC, etc. were selected as the first batch of training bases for "Enterprise Digital Transformation and Security Capability Improvement" by the Ministry of Industry and Information Te









