ES6中的Promise、async、await,超详细讲解!

时间:2024-12-19 21:37:16

Promise是es6引入的异步编程新解决方案,Promise实例和原型上有reject、resolve、all、then、catch、finally等多个方法,语法上promise就是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果,本篇文章主要介绍了ES6中的Promise对象与async和await方法,创作不易,如果能帮助到带大家,欢迎收藏+关注 哦 ????

????????文章目录

Promise

promise状态

执行次序

示例1

示例2

链式调用

链式传值

catch对调用链的影响

catch处在最后

catch处在中间

async & await

async

await

Promise

promise状态

Promise总是处于以下三种状态之一:

  • pending:初始状态
  • fulfilled/resolved:表示成功
  • rejected:表示失败

状态有一些特性:

  • 只能通过执行函数修改
  • 外部无法读取
  • 外部无法修改

Promise实例添加处理程序的主要方法,接收的两个参数分别表示进入fulfilled/resolvedrejected状态时被调用,且二者互斥。两个参数可选,但必须是函数类型,非函数类型会被忽略。一个Promise实例可以有任意多个处理程序(任意多个then调用

等价于(null,onRejected)

无论状态是fulfilled/resolved还是rejected都会执行,但无法得知具体的状态(状态无关),一般主要用于清理工作

执行次序

示例1
  1. const p = new Promise(resolve => {
  2. console.log('1. excute promise');
  3. setTimeout(() => {
  4. console.log('3. before resolve')
  5. resolve();
  6. console.log('4. after resolve')
  7. }, 100);
  8. })
  9. p.then(() => {
  10. console.log('5. execute resolve')
  11. }).then(()=>{
  12. console.log('6. then2')
  13. }).then(()=>{
  14. console.log('7. then3')
  15. }).finally(()=>{
  16. console.log('8. finally')
  17. });
  18. console.log('2. sync then')
  19. /**
  20. result:
  21. 1. excute promise
  22. 2. sync then
  23. 3. before resolve
  24. 4. after resolve
  25. 5. execute resolve
  26. 6. then2
  27. 7. then3
  28. 8. finally
  29. */
'
运行
示例2
  1. const p = new Promise(resolve => {
  2. setTimeout(() => {
  3. resolve();
  4. }, 100);
  5. })
  6. p.then(()=>{
  7. console.log('then1')
  8. }).then(()=>{
  9. console.log('then2')
  10. }).then(()=>{
  11. console.log('then3')
  12. }).then(()=>{
  13. console.log('then4')
  14. }).then(()=>{
  15. console.log('then5')
  16. });
  17. console.log('async then')
  18. /**
  19. result:
  20. async then
  21. then1
  22. then2
  23. then3
  24. then4
  25. then5
  26. */
'
运行

这个示例中then1then2then3then4then5相当于是同步执行的

链式调用

then的链式调用是Promise最常见的用法,具体方式是每个执行器返回一个Promise实例,则后续每个then都会等待前一个落定后再执行,即异步的串行化。以此来解决异步的回调地狱难题。

es6规范不支持Promise终止与进度查询,原因是这样会使得Promise变得过于复杂。

链式传值
  1. const p = new Promise(resolve => {
  2. setTimeout(() => {
  3. resolve(100);
  4. }, 100);
  5. })
  6. p.then(value => {
  7. console.log(value)
  8. return value + 1;
  9. }).then(value => {
  10. console.log(value)
  11. return new Promise(resolve => {
  12. setTimeout(() => {
  13. resolve(value + 1)
  14. }, 3000);
  15. });
  16. }).then(value => {
  17. console.log(value)
  18. return value + 1;
  19. }).then(value => {
  20. console.log(value)
  21. return value + 1;
  22. }).then(value => {
  23. console.log(value)
  24. return value + 1;
  25. });
  26. /**
  27. 100
  28. 101
  29. 102 等待3秒
  30. 103
  31. 104
  32. */
'
运行

如果执行函数返回的是一个Promise对象,则后续的调用会等待该对象落定后触发,通过resolve方式传值;如果不是,则后续立即触发,通过return语句向后传值

catch对调用链的影响

catch处在最后
  1. const p = new Promise(resolve => {
  2. setTimeout(() => {
  3. resolve(100);
  4. }, 100);
  5. })
  6. p.then(value => {
  7. console.log(value)
  8. return value + 1;
  9. }).then(value => {
  10. console.log(value)
  11. return new Promise((resolve, reject) => {
  12. setTimeout(() => {
  13. reject('fail')
  14. }, 3000);
  15. });
  16. }).then(value => {
  17. console.log(value)
  18. return value + 1;
  19. }).then(value => {
  20. console.log(value)
  21. return value + 1;
  22. }).then(value => {
  23. console.log(value)
  24. return value + 1;
  25. }).catch(err => {
  26. console.log('catch', err);
  27. return new Promise((resolve, reject) => {
  28. setTimeout(() => {
  29. resolve(400)
  30. }, 3000);
  31. });
  32. });
  33. /**
  34. 100
  35. 101
  36. catch fail
  37. */
'
运行

catch处在调用链最后的时候,则reject后续的then将不会被触发

catch处在中间
  1. const p = new Promise(resolve => {
  2. setTimeout(() => {
  3. resolve(100);
  4. }, 100);
  5. })
  6. p.then(value => {
  7. console.log(value)
  8. return value + 1;
  9. }).then(value => {
  10. console.log(value)
  11. return new Promise((resolve, reject) => {
  12. setTimeout(() => {
  13. reject('fail')
  14. }, 3000);
  15. });
  16. }).then(value => {
  17. console.log(value)
  18. return value + 1;
  19. }).catch(err => {
  20. console.log('catch', err);
  21. return 500;
  22. }).then(value => {
  23. console.log(value)
  24. return value + 1;
  25. }).then(value => {
  26. console.log(value)
  27. return value + 1;
  28. });
  29. /**
  30. 100
  31. 101
  32. catch fail
  33. */
'
运行

catch处在调用链中间,如果返回的不是一个Promise对象,后续的then将不会被触发

async & await

async

语法:

  1. async function name([param[, param[, ... param]]]) {
  2. statements
  3. }
  • name:函数名称
  • param:要传递给函数的参数的名称
  • statements:包含函数主体的表达式,可以使用await机制
  • 返回值:一个Promise,这个Promise要么会通过一个由async函数返回的值被解决,要么会通过一个从async函数中抛出的(或其中没有被捕获到的)异常被拒绝

async关键字用于声明异步函数,可以用在函数声明、函数表达式、箭头函数、方法上:

  1. async function foo() {}
  2. let bar = async function () {}
  3. let baz = async () => {}
  4. class Person{
  5. async say(){}
  6. }
'
运行

异步函数如果使用return关键字返回了值,则这个值会被()包装成一个Promise对象

  1. async function test() {
  2. return 2;
  3. }
  4. test().then(value => {
  5. console.log(value)
  6. })
  7. console.log(1)
  8. /**
  9. 1
  10. 2
  11. */
'
运行

如果函数体中抛出了异常,可以用catch处理:

  1. async function test() {
  2. const result = 100 / a;
  3. return result;
  4. }
  5. test().catch(value => {
  6. console.log(value)
  7. })
  8. console.log(1)
  9. /**
  10. 1
  11. ReferenceError: a is not defined
  12. */
'
运行

一些资料中会说拒绝Promise的异常不被异步函数捕获,但在最新版的Chrome(95.0.4638.69)Microsoft Edge(95.0.1020.40)Firefox(93.0)都是支持的:

  1. async function test() {
  2. return Promise.reject('error');
  3. }
  4. test().catch(value => {
  5. console.log(value)
  6. })
  7. console.log(1)
  8. /**
  9. 1
  10. error
  11. */
'
运行

await

语法:

[返回值] = await 表达式;

  • 表达式:一个Promise对象或者任何要等待的值
  • 返回值:返回Promise对象的处理结果。如果等待的不是Promise对象,则返回该值本身

在用法上,await可以单独使用,也可以在表达式中使用:

  1. async function func(){
  2. console.log(await Promise.resolve('foo'))
  3. }
  4. func();
  5. /**
  6. foo
  7. */
'
运行

await只能在async函数内顶层使用,不支持嵌套

 在使用多个await关注其结果,忽视其顺序有时候是个好事,因为不同的规范对于await处理Promise是有差异的。

???? 个人简介:某大型国企资深软件开发工程师,信息系统项目管理师、****优质创作者、阿里云专家博主、华为云云享专家,分享前端后端相关技术与工作常见问题~

???? 作    者:码喽的自我修养❣️
???? 专    栏:JavaScript深入研究

???? 若有帮助,还请 关注➕点赞➕收藏 ,不行的话我再努努力???????????? 

  更多专栏订阅推荐:

???? vue2/3 从基础到起飞

???? JavaScript深入研究

???? 前端工程搭建
???? javaScript基础

✈️ HTML5与CSS3

⭐️ uniapp与微信小程序

???? 前端工作常见问题汇总

✍️ GIS地图与大数据可视化

???? 常用组件库与实用工具