当前位置:网站首页>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() 与之前的函数是相同的。
边栏推荐
- vector类
- 从零开始搭建MySQL主从复制架构
- 请问下这个hologres维表是被缓存了么?怎么直接Finished了
- Hannah荣获第六季完美童模全球总决赛全球人气总冠军
- 数字资产的价值激发:NFT 质押
- Web3 安全风险令人生畏?应该如何应对?
- How to write SQL statements in DataWorks monitoring data reaches a certain value to indicate the change of
- protobuf 反射使用总结
- LeetCode·72.编辑距离·动态规划
- [Unity Getting Started Plan] Basic Concepts (7) - Input Manager & Input Class
猜你喜欢

TiKV & TiFlash accelerate complex business queries丨TiFlash application practice

从零开始搭建MySQL主从复制架构

产品-Axure9英文版,轮播图效果

罗克韦尔AB PLC RSLogix5000中创建新项目、任务、程序和例程的具体方法和步骤

组件通信--下拉菜单案例

error:Illegal instruction (core dumped),离线下载安装这个other版本numpy

高效的组织信息共享知识库是一种宝贵的资源

LeetCode·72.编辑距离·动态规划

使用.NET简单实现一个Redis的高性能克隆版(一)

Components of communication - the drop-down menu
随机推荐
Detailed explanation of setting HiSilicon MMZ memory and OS memory
ArkUI如何适配横竖屏
从零开始搭建MySQL主从复制架构
C专家编程 第3章 分析C语言的声明 3.8 理解所有分析过程的代码段
C专家编程 第3章 分析C语言的声明 3.6 typedef int x[10]和#define x int[10]的区别
C语言03、数组
EA 改口,称单人游戏是产品组合中“非常重要的一部分”
使用uniapp 封装一个request 请求
元宇宙系列--Value creation in the metaverse
MySQL查询语法
Async的线程池使用的哪个?
The strongest distributed lock tool: Redisson
Auto Scaling 弹性伸缩(运维释放人力)
leetcode SVM
华为、联想、北汽等入选工信部“企业数字化转型和安全能力提升”首批实训基地
“LaMDA 存在种族歧视,谷歌的 AI 伦理不过是‘遮羞布’!”
附录A 程序员工作面试的秘密
组件通信-父传子组件通信
node连接mongoose数据库流程
《社会企业开展应聘文职人员培训规范》团体标准在新华书店上架