阅读 155

ES6中的Promise、async、await

Promise

状态

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

  • pending:初始状态

  • fulfilled/resolved:表示成功

  • rejected:表示失败

状态有一些特性:

  • 只能通过执行函数修改

  • 外部无法读取

  • 外部无法修改

Promise.prototype.then

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

Promise.prototype.catch

等价于Promise.prototype.then(null,onRejected)

Promise.prototype.finally

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

执行次序

示例1

const p = new Promise(resolve => {     console.log('1. excute promise');     setTimeout(() => {         console.log('3. before resolve')         resolve();         console.log('4. after resolve')     }, 100); }) p.then(() => {     console.log('5. execute resolve') }).then(()=>{     console.log('6. then2') }).then(()=>{     console.log('7. then3') }).finally(()=>{     console.log('8. finally') }); console.log('2. sync then') /** result: 1. excute promise 2. sync then 3. before resolve 4. after resolve 5. execute resolve 6. then2 7. then3 8. finally */ 复制代码

示例2

const p = new Promise(resolve => {     setTimeout(() => {         resolve();     }, 100); }) p.then(()=>{     console.log('then1') }).then(()=>{     console.log('then2') }).then(()=>{     console.log('then3') }).then(()=>{     console.log('then4') }).then(()=>{     console.log('then5') }); console.log('async then') /** result: async then then1 then2 then3 then4 then5 */ 复制代码

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

链式调用

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

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

链式传值

const p = new Promise(resolve => {     setTimeout(() => {         resolve(100);     }, 100); }) p.then(value => {     console.log(value)     return value + 1; }).then(value => {     console.log(value)     return new Promise(resolve => {         setTimeout(() => {             resolve(value + 1)         }, 3000);     }); }).then(value => {     console.log(value)     return value + 1; }).then(value => {     console.log(value)     return value + 1; }).then(value => {     console.log(value)     return value + 1; }); /** 100 101 102 等待3秒 103 104 */ 复制代码

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

catch对调用链的影响

catch处在最后
const p = new Promise(resolve => {     setTimeout(() => {         resolve(100);     }, 100); }) p.then(value => {     console.log(value)     return value + 1; }).then(value => {     console.log(value)     return new Promise((resolve, reject) => {         setTimeout(() => {             reject('fail')         }, 3000);     }); }).then(value => {     console.log(value)     return value + 1; }).then(value => {     console.log(value)     return value + 1; }).then(value => {     console.log(value)     return value + 1; }).catch(err => {     console.log('catch', err);     return new Promise((resolve, reject) => {         setTimeout(() => {             resolve(400)         }, 3000);     }); }); /** 100 101 catch fail */ 复制代码

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

catch处在中间
const p = new Promise(resolve => {     setTimeout(() => {         resolve(100);     }, 100); }) p.then(value => {     console.log(value)     return value + 1; }).then(value => {     console.log(value)     return new Promise((resolve, reject) => {         setTimeout(() => {             reject('fail')         }, 3000);     }); }).then(value => {     console.log(value)     return value + 1; }).catch(err => {     console.log('catch', err);     return 500; }).then(value => {     console.log(value)     return value + 1; }).then(value => {     console.log(value)     return value + 1; }); /** 100 101 catch fail */ 复制代码

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

async & await

async

语法:

async function name([param[, param[, ... param]]]) {    statements } 复制代码

  • name:函数名称

  • param:要传递给函数的参数的名称

  • statements:包含函数主体的表达式,可以使用await机制

  • 返回值:一个Promise,这个Promise要么会通过一个由async函数返回的值被解决,要么会通过一个从async函数中抛出的(或其中没有被捕获到的)异常被拒绝

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

async function foo() {} let bar = async function () {} let baz = async () => {} class Person{     async say(){} } 复制代码

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

async function test() {     return 2; } test().then(value => {     console.log(value) }) console.log(1) /** 1 2 */ 复制代码

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

async function test() {     const result = 100 / a;     return result; } test().catch(value => {     console.log(value) }) console.log(1) /** 1 ReferenceError: a is not defined */ 复制代码

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

async function test() {     return Promise.reject('error'); } test().catch(value => {     console.log(value) }) console.log(1) /** 1 error */ 复制代码

await

语法:

[返回值] = await 表达式;

  • 表达式:一个Promise对象或者任何要等待的值

  • 返回值:返回Promise对象的处理结果。如果等待的不是Promise对象,则返回该值本身

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

async function func(){     console.log(await Promise.resolve('foo')) } func(); /** foo */ 复制代码

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

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


作者:啦萌朵
链接:https://juejin.cn/post/7025861965645873165


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐