• 技术文章 >web前端 >前端问答

    async属于es6属性吗

    青灯夜游青灯夜游2022-10-20 15:02:11原创160

    属于,async是es6的新特性,用于表明程序里面可能有异步过程。用async关键字声明的函数返回的是一个Promise对象,如果在函数中return一个直接量,async会把这个直接量通过Promise.resolve()封装成Promise对象;当async函数没有返回值时,返回“Promise.resolve(undefined)”。

    大前端成长进阶课程:进入学习

    本教程操作环境:windows7系统、ECMAScript 6版、Dell G3电脑。

    ES6新特性 async和await关键字

    1、初步了解

    我们先从字面意思来理解这两个关键字,async是asynchronous(异步)的简写,而await可以认为是async wait的简写。所以async可以理解为用于声明一个函数是异步的,而await用于等待一个异步任务执行完成。

    async和await关键字让我们可以用一种更简洁的方式写出基于promise的异步行为,而无需刻意地链式调用promise。

    接下来我们通过先几个例子,初步了解一下async和await的作用。

    知识点1: 用 async 关键字声明的函数返回的是一个 Promise 对象。如果在函数中 return 一个直接量,async 会把这个直接量通过 Promise.resolve() 封装成 Promise 对象。当 async 函数没有返回值时,返回 Promise.resolve(undefined)

     //定义一个普通函数,返回一个字符串
     function test() {
         return "hello async";
     }
     const result1 = test();
     console.log(result1); //输出一个字符串 hello async
     
     //定义一个使用了async修饰的函数,同样返回一个字符串
     async function testAsync() {
         return "hello async";
     }
     const result2 = testAsync();
     console.log(result2); //输出一个Promise对象 Promise {<fulfilled>: 'hello async'}
     //async较好的用法
     async function testAsync(){
         //返回一个Promise对象
         return new Promise((resolve, reject)=>{
             //处理异步任务
             setTimeout(function () {
                 resolve("testAsync")
             }, 1000);
         })
     }
     //async通常用于声明一个处理异步任务且返回了Promise对象的函数

    知识点2: await关键字只能使用在被async声明的函数内,用于修饰一个Promise对象,使得该Promise对象处理的异步任务在当前协程上按顺序同步执行。

     //定义一个使用async修饰的函数,处理异步任务
     async function testAsync(){
         return new Promise((resolve, reject)=>{
             setTimeout(function () {
                 resolve("testAsync")
             }, 1000);
         })
     }
     //定义一个函数,直接调用testAsync函数
     function testAwait(){
         console.log('testAsync调用前')
         testAsync().then(res=>{
             console.log(res) //输出"testAsync"
         })
         console.log('testAsync调用后')
     }
     
     /***** 输出如下 *****/
     testAsync调用前
     testAsync调用后
     testAsync
     //尽管代码按顺序写,但不按顺序执行,因为testAsync()是异步函数
     //定义一个函数(不使用async声明该函数)用await修饰调用testAsync函数
     function testAwait(){
         console.log('testAsync调用前')
         await testAsync().then(res=>{ //使用await关键字修饰
             console.log(res)
         })
         console.log('testAsync调用后')
     }
     
     //调用testAwait()函数
     testAwait()
     //报错:Uncaught SyntaxError: await is only valid in async functions and the top level bodies of modules,因为await只能使用在被async修饰的函数内。
     //定义一个函数(使用async声明该函数)用await修饰调用testAsync函数
     async function testAwait(){
         console.log('testAsync调用前')
         await testAsync().then(res=>{
             console.log(res)
         })
         console.log('testAsync调用后')
     }
     
     /***** 输出如下 *****/
     testAsync调用前
     testAsync
     testAsync调用后
     
     //使用了await关键字修饰,使得代码按照顺序执行,即同步执行

    2、async关键字

    (1)用于表明程序里面可能有异步过程

    (2)async函数返回值的类型为Promise对象: 这是和普通函数本质上不同的地方,也是使用时重点注意的地方;

    (3)无等待,非阻塞:使用async关键字声明的函数里面如果有异步过程可能会等待,但是函数本身会马上返回,不会阻塞当前主线程。如果在函数里面使用了await关键字修饰的异步过程,其工作在相应的协程上,会阻塞等待异步任务的完成再返回。

     //定义一个函数,处理异步任务(使用定时器模拟),返回一个Promise对象
     async function testAsync(){
         return new Promise((resolve, reject) => {
           setTimeout(function () {
             resolve("成功调用testAsync")
           }, 1000);
         });
     }
     
     //定义一个函数,使用await关键字修饰调用testAsync()函数
     async function testAwait(){
         //使用了await关键字修饰调用testAsyn()函数
         await this.testAsync().then(res=>{
           console.log(res) //输出的是testAsync()函数resolve的值
         });
         console.log("helloAsync");
     }
     
     //主线程
     console.log('testAwait调用前')
     testAwait();
     console.log('testAwait调用后')
     
     /***** 输出结果如下 *****/
     testAwait调用前
     testAwait调用后 //因为testAwait()函数使用了async关键字修饰,所以不会阻塞主线程的执行,所以这两句话会先直接输出,然后再执行testAwait()函数
     成功调用testAsync //因为testAwait()函数在内部调用testAsync()函数时使用了await关键字修饰,所以在对应的协程上会阻塞,等待testAsync()函数执行完,再输出下面那句'helloAsync'
     helloAsync

    3、await关键字

    (1)await只能在async函数内部使用:不能放在普通函数里面,否则会报错。

    (2)await关键字后面跟的是一个Promise对象。如果跟的是一个函数,则这个函数应当返回一个Promise对象。如果跟的是非Promise对象,则会通过Promise.resolve( )函数自动将这个东西包装成一个Promise对象并置于fulfilled状态。

     //例如:
     const a = await 'Hello Await'
     // 相当于
     const a = await Promise.resolve('Hello Await');
     
     console.log(a) //输出 'Hello Await'

    (3)await的本质是等待它所修饰的Promise对象的fulfilled状态,并把resolve(data)的数据data返回。

    意思是,如果await后面跟的是一个 Promise 对象,await 就会阻塞后面的代码,等着 Promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果。

     async function testAsync(){
         return new Promise((resolve, reject) => {
           setTimeout(function () {
             resolve("成功调用testAsync")
           }, 1000);
         });
     }
     
     const a = await testAsync() //这里的a就会拿到testAsync函数resolve的数据
     console.log(a) //在一秒后输出'成功调用testAsync'

    (4)await并不关心它所修饰的Promise对象的rejected状态,即reject(data)的数据data并不会被await处理,所以建议通过Promise对象调用catch去捕获。

     async testAwait(){
         //变量a用于接收testAsync()函数resolve的数据
         let a = await testAsync().catch(err=>{
             //处理异常和reject的数据
         })    
     }

    4、深入讲解async和await

    (1)执行顺序

     //定义一个函数,该函数接收一个参数,1s后再返回参数的两倍
     async function double(num) {
         return new Promise((resolve, reject) => {
             setTimeout(() => { //使用定时器模拟异步任务
                 resolve(2 * num) //将运算结果交给resolve
             }, 1000);
         })
     }
     
     async function getResult () {
         console.log('double调用前')  //顺序:2
         let result = await double(10); //将10作为参数传递给double函数
         //result变量用于接收double()函数resolve的值
         console.log(result); //顺序:4
         console.log('double调用后') //顺序:4
     }
     
     console.log('getResult调用前') //顺序:1
     getResult();
     console.log('getResult调用后') //顺序:3
     
     /***** 依次输出如下 *****/
     getResult调用前
     double调用前
     getResult调用后
     20 //1s后输出
     double调用后

    ①首先打印输出getResult调用前,同步代码,顺序执行;

    ②然后调用方法getResult( ),打印输出double调用前,同步代码,顺序执行;

    ③再调用异步方法double( )

    如果此处没有使用await关键字修饰,则依次输出的是:getResult调用前、double调用前、double调用后、getResult调用后、1s后输出20

    因为异步操作不会影响其他代码的执行,所以会将其他代码按顺序执行完,最后再执行double函数

    因为这里使用了await关键字,所以getResult( )的代码执行到这里就会被阻塞,等到double函数resolve了,再往下执行

    ④尽管getResult函数内部被await阻塞了,由于getResult函数本身也是个async函数,所以它不会影响getResult函数外面的代码执行。因为调用async函数不会造成阻塞,它内部的所有阻塞都被封装在一个Promise对象中异步执行。

    ⑤所以在调用getResult函数后,会继续向下执行,即打印输出getResult调用后

    ⑥当1s之后,异步函数double执行完成,将结果交给resolve。

    ⑦通过await关键字接收到double函数resolve的值,赋值给result变量。打印输出20

    ⑧因为使用了await阻塞将异步变为同步,所以在打印输出20后再打印输出double调用后

    (2)处理reject回调

     //方法一:通过promise对象的catch进行捕获
     function a(){
         return new Promise((resolve,reject) => {
             setTimeout(() => {
                 reject("something")
             }, 1000)
         })
     }
     
     async function b(){
         let r = await a().catch((err)=>{
             console.log(err)
         })
     }
     //方法二:通过try/catch语句处理
     function a(){
         return new Promise((resolve,reject) => {
             setTimeout(() => {
                 reject("something")
             }, 1000)
         })
     }
     
     async function b(){
         let r = null
         try{
            r = await a()
         }catch(err){
             console.log(err)
         }
     }

    (3)使用await优化Promise对象的回调地狱问题

    在Promise章节中我们通过了Promise对象的then( )方法链式调用解决了回调地狱问题,但看起来仍然不够美观,我们可以通过await优化一下,让它看起来更符合我们平时代码的编写习惯。

     //原本的解决方案
     //第二个请求依赖于第一个请求的返回值,第三个请求依赖于第二个请求的返回值
     request1().then(function(data){ 
         return request2(data)
     }).then(function(data){ 
         return request3(data)
     })
     //这里只发送了三次请求,代码看起来还不错,虽然它已经比普通的回调函数形式好了很多。
     //那如果需要发送五次或十次请求呢?代码也许会没那么美观,接下来我们使用学习到的await去解决这个问题。

    原本的要求是每个请求都依赖于上一个请求的返回值,那么是不是得等一个请求完,才能发送下一个请求?这时我们可以思考一下,await的作用是什么?是不是对一个Promise对象去进行阻塞,使其状态变为fulfilled后获取resolve的值。这不就正是我们所需要的。

     //使用await的解决方案
     var res1 = await request1() //将request1的返回值赋值给res1
     var res2 = await request2(res1) //将res1作为参数传给request2,并将request2的返回值赋值给res2
     var res3 = await request3(res2) //同理
     
     //这样子写的代码更加的美观,并且更符合我们平时编写代码的习惯

    【相关推荐:javascript视频教程编程视频

    以上就是async属于es6属性吗的详细内容,更多请关注php中文网其它相关文章!

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。

    前端(VUE)零基础到就业课程:点击学习

    清晰的学习路线+老师随时辅导答疑

    自己动手写 PHP MVC 框架:点击学习

    快速了解MVC架构、了解框架底层运行原理

    专题推荐:javascript ES6
    上一篇:typescript兼容es6吗 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • ❤️‍🔥共22门课程,总价3725元,会员免费学• ❤️‍🔥接口自动化测试不想写代码?• javascript怎么正则替换非汉字的字符• javascript怎么求数组中的最大奇数• JavaScript怎么输入N个数据求平均数• 一文详解JavaScript中执行上下文与执行栈(图文结合)• javascript怎么求总分和平均值• javascript有没有返回值
    1/1

    PHP中文网