ES6中Promise、async、await用法超详细讲解指南

 更新时间:2024年08月09日 10:29:16   作者:码喽的自我修养  
async+await是ES6中引入的异步编程解决方案,旨在解决异步编程中的回调地狱问题,下面这篇文章主要给大家介绍了关于ES6中Promise、async、await用法超详细讲解的相关资料,需要的朋友可以参考下

Promise

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是有差异的。

总结 

到此这篇关于ES6中Promise、async、await用法超详细讲解指南的文章就介绍到这了,更多相关ES6 Promise、async、await内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Js 导出table内容到Excel的简单实例

    Js 导出table内容到Excel的简单实例

    在做前端开发时,常常会用到通过js把数据导入到excel的功能,现在给出给简单demo代码,以供以后使用
    2013-11-11
  • javascript改变position值实现菜单滚动至顶部后固定

    javascript改变position值实现菜单滚动至顶部后固定

    现在很多网站都有这样的一个效果,当页面滚动到一定高度时,菜单栏会固定在页面顶部;该效果在 ie6 下不支持,因为ie6不支持 position:fixed,效果很不错,感兴趣的朋友可以了解下啊
    2013-01-01
  • IntersectionObserver实现图片懒加载的示例

    IntersectionObserver实现图片懒加载的示例

    下面小编就为大家带来一篇IntersectionObserver实现图片懒加载的示例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • JS实现数组的增删改查操作示例

    JS实现数组的增删改查操作示例

    这篇文章主要介绍了JS实现数组的增删改查操作,结合实例形式分析了javascript针对数组的追加、获取、删除、添加、修改等常见操作技巧与相关注意事项,需要的朋友可以参考下
    2018-08-08
  • Blob对象实现文件上传下载示例详解

    Blob对象实现文件上传下载示例详解

    这篇文章主要为大家介绍了Blob对象实现文件上传下载示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • 详解JavaScript中map()和forEach()的异同

    详解JavaScript中map()和forEach()的异同

    在JavaScript中,map()和forEach()是两个常用的数组方法,它们都用于遍历数组,但在某些方面有一些关键的区别,本文将详细讨论这两种方法的异同,以帮助您更好地理解它们的用法和适用场景,需要的朋友可以参考下
    2024-02-02
  • uni app跨端自定义指令实现按钮权限

    uni app跨端自定义指令实现按钮权限

    这篇文章主要为大家介绍了uni app跨端自定义指令实现按钮权限详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • javascript适配器模式和组合模式原理与实现方法详解

    javascript适配器模式和组合模式原理与实现方法详解

    这篇文章主要介绍了javascript适配器模式和组合模式原理与实现方法,结合实例形式详细分析了javascript适配器模式与组合模式相关原理、功能、实现方法与注意事项,需要的朋友可以参考下
    2023-07-07
  • JavaScript前端开发之实现二进制读写操作

    JavaScript前端开发之实现二进制读写操作

    这篇文章主要介绍了JavaScript前端开发之实现二进制读写操作的相关资料,需要的朋友可以参考下
    2015-11-11
  • Javascript类型转换详解

    Javascript类型转换详解

    这篇文章主要为大家介绍了Javascript类型转换,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01

最新评论