zoukankan      html  css  js  c++  java
  • javascript 中 async/await 的用法

    https://www.cnblogs.com/liquanjiang/p/11409792.html 转自

    https://www.cnblogs.com/bear-blogs/p/10423759.html 参考

    https://www.cnblogs.com/CandyManPing/p/9384104.html

    await 操作符

    MDN 是这样描述 await 的:

    await 表达式会暂停当前 async function 的执行,等待 Promise 处理完成。若 Promise 正常处理(fulfilled),其回调的resolve函数参数作为 await 表达式的值,继续执行async function。若 Promise 处理异常(rejected),await 表达式会把 Promise 的异常原因抛出。另外,如果 await 操作符后的表达式的值不是一个 Promise,则返回该值本身。

     阮一峰老师的解释我觉得更容易理解:

    async 函数返回一个 Promise 对象,当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句。

    按照mdn解释 await会暂停当前async 函数执行,并且await 后面是一个表达式,即这个await 等待的是一个表达式(这个表达式返回promise 对象或者一个具体的值):

    •   假如这个表达式如果返回的是一个Promise 对象, 那么它的返回值,实际上就是 Promise 的回调函数 resolve 的参数,如果这个Promise rejected 了,await 表达式会把 Promise 的异常抛出。
    •   假如这个表达式如果返回的是一个常量,那么会把这个常量转为Promise.resolve(xx),同理如果没有返回值也是Promise.resolve(underfind)

    我的理解是,await表达式后面的promise状态是成功,那么resolve函数的参数就是await表达式的值 ,然后继续执行async function,但是如果promise状态是rejected或者抛出异常,await表达式会吧promose的异常原因抛出,然后就不执行async function await之后的语句了

    一、async

    带async关键字的函数,是声明异步函数,返回值是promise对象,如果async关键字函数返回的不是promise,会自动用Promise.resolve()包装。

    async function test() {
        return 'test'
    }
    test();

    返回值为 Promise {<resolved>: "test"}。

    二、await

    await等待右侧表达式的结果,这个结果是promise对象或者其他值。
    如果它等到的不是一个 promise 对象,那 await 表达式的运算结果就是它等到的东西。
    如果它等到的是一个 promise 对象,await 就忙起来了,它会阻塞后面的代码,等着 promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果。

    复制代码
    function test() {
        return new Promise(resolve => {
            setTimeout(() => resolve("test"), 2000);
        });
    }
    
    const result = await test();
    console.log(result);
    console.log('end')
    复制代码

    由于test()造成的阻塞,console.log('end')会等到两秒后执行

    所以为了避免造成阻塞,await 必须用在 async 函数中,async 函数调用不会造成阻塞。

    复制代码
    function test() {
        return new Promise(resolve => {
            setTimeout(() => resolve("test"), 2000);
        });
    }
    
    async function test2() {
        const result = await test();
        console.log(result);
    }
    test2();
    console.log('end');
    复制代码

    先执行console.log('end'),两秒后执行console.log('test')

    如果await用在普通函数中,会报错,如下:

    三、async/await的执行顺序

    遇到await会阻塞后面的代码,先执行async外面的同步代码,同步代码执行完,再回到async内部,继续执行await后面的代码。以下面的代码分析:

    复制代码
            async function test1() {
                console.log('start test1');
                console.log(await test2());
                console.log('end test1');
            }
            async function test2() {
                console.log('test2');
                return await 'return test2 value'
            }
            test1();
            console.log('start async');
            setTimeout(() => {
                console.log('setTimeout');
            }, 0);
            new Promise((resolve, reject) => {
                console.log('promise1');
                resolve();
            }).then(() => {
                console.log('promise2');
            });
            console.log('end async');
    复制代码

    执行的结果

    · 首先执行宏任务,执行test1函数,执行console.log('statr test1')

    · 遇到await,先执行右边test2中的console.log('test2'),中断了后面的代码,执行test1外面的同步代码

    · 执行console.log('start async');

    · 遇到setTimeout,推到到下个宏任务队列中

    · 执行Promise里面的同步代码console.log('promise1')

    · 运行到promise().then,发现是promise对象,推到微任务队列中

    · 执行console.log('end async')

    · test1外面的同步代码执行结束后,回到test1中,console.log(await test2())执行完成后返回Promise {<resolved>: "return test2 value"},是promise对象,推到微任务队列中

    · 此时第一个宏任务结束,执行所有的微任务,因为微任务队列先进先出,所以先执行console.log('promise2'),后执行console.log('return test2 value')

    · 执行test2完成后,后面的代码不再阻塞,执行console.log('end test1');

    · 执行下个宏任务,即执行console.log('setTimeout');

    补充下有关宏任务和微任务的知识

    宏任务和微任务都是队列,宏任务有script、setTimeout、setInterval等,微任务有Promise.then catch finally、process.nextTick等,宏任务和微任务的关系如下:

    先执行第一个宏任务,执行结束后,执行所有的微任务,然后执行下个宏任务。

    四、async/await的优缺点

    1. 优点

    相对于promise,async/await处理 then 的调用链,代码要清晰很多,几乎和同步代码一样

    2. 缺点

    滥用 await 可能会导致性能问题,因为 await 会阻塞代码

    五、处理reject

    1. try/catch

    复制代码
            async function fn() {
                try {
                    await new Promise((resolve, reject) => {
                    setTimeout(() => {
                        reject('err3');
                    }, 1000);
                })
                } catch (err){
                    alert(err)
                }
            }
            fn()
    复制代码

    2. catch

    复制代码
           async function fn() {
                await new Promise((resolve, reject) => {
                    setTimeout(() => {
                        reject('err');
                    }, 1000);
                })
            }
            fn().catch(alert)
    复制代码

    1、首先需要理解async 和 await的基本含义

       async 是一个修饰符,async 定义的函数会默认的返回一个Promise对象resolve的值,因此对async函数可以直接进行then操作,返回的值即为then方法的传入函数

    复制代码
    // 0. async基础用法测试
    
    async function fun0() {
        console.log(1)
        return 1
    }
    
    fun0().then( x => { console.log(x) })  //  输出结果 1, 1,
    
    
    async function funa() {
        console.log('a')
        return 'a'
    }
    
    funa().then( x => { console.log(x) })  //  输出结果a, a,
    
    
    async function funo() {
        console.log({})
        return {}
    }
    
    funo().then( x => { console.log(x) })   // 输出结果 {}  {}
    
    async function funp() {
        console.log('Promise')
        return new Promise(function(resolve, reject){
            resolve('Promise')
        })
    }
    
    funp().then( x => { console.log(x) })   // 输出promise  promise
    复制代码

    await 也是一个修饰符,

    await 关键字 只能放在 async 函数内部, await关键字的作用 就是获取 Promise中返回的内容, 获取的是Promise函数中resolve或者reject的值
    // 如果await 后面并不是一个Promise的返回值,则会按照同步程序返回值处理

    复制代码
    //  await 关键字 只能放在 async 函数内部, await关键字的作用 就是获取 Promise中返回的内容, 获取的是Promise函数中resolve或者reject的值
    // 如果await 后面并不是一个Promise的返回值,则会按照同步程序返回值处理,为undefined
    const bbb = function(){ return 'string'}
    
    async function funAsy() {
       const a = await 1
       const b = await new Promise((resolve, reject)=>{
            setTimeout(function(){
               resolve('time')
            }, 3000)
       })
       const c = await bbb()
       console.log(a, b, c)
    }
    
    funAsy()  //  运行结果是 3秒钟之后 ,输出 1, time , string,
    复制代码
    复制代码
    // 2.如果不使用promise的方法的话
    
    function log2(time) {
       setTimeout(function(){
           console.log(time)
           return 1
        }, time)
    }
    
    async function fun1() {
        const a = await log2(5000)
        const b = await log2(10000)
        const c = log2(2000)
        console.log(a)
        console.log(1)
    }
    
    fun1()
    
    // 以上运行结果为: 立刻输出undefined   立刻输出1  2秒后输出2000  5秒后输出5000  10秒后输出10000
    复制代码

    2、那么由此看来async / await的综合用法如下

    复制代码
    // 1.定义一个或多个普通函数,函数必须返回Promise对象,如果返回其他类型的数据,将按照普通同步程序处理
    
    function log(time) {
        return new Promise((resolve, reject)=> {
            setTimeout(function(){
               console.log(time)
               resolve()
            }, time)
        })
    }
    
    async function fun() {
        await log(5000)
        await log(10000)
        log(1000)
        console.log(1)
    }
    
    fun()
    复制代码
    复制代码
    // 3. async / await的重要应用 
    
    const asy = function(x, time) {
        return new Promise((resolve, reject) =>{
            setTimeout(()=>{
                resolve(x)
            }, time)
        })
    }
    
    const add = async function() {
        const a = await asy(3, 5000)
        console.log(a)
        const b = await asy(4, 10000)
        console.log(b)
        const c =  await asy(5, 15000)
        console.log(a,b,c)
        const d = a + b +c  
        console.log(d)
    }
    
    add();
    
    // 5秒后输出3  又10秒后输出4 又15秒后输出5  然后立刻输出3,4,5,然后输出12
    复制代码
  • 相关阅读:
    【OS_Windows】用微pe制作启动盘安装操作系统
    技术列表
    RPC 的概念模型与实现解析
    asp.net站点阻止某个文件夹或者文件被浏览器访问
    常用插件
    安全相关
    asp.net mvc 请求处理流程,记录一下。
    接口的显示实现和隐式实现
    值类型与引用类型的简单测试,没有太多的理论,一目了然。
    IEnumerable、GetEnumerator、IEnumerator之间的关系。
  • 原文地址:https://www.cnblogs.com/lonelyshy/p/13726674.html
Copyright © 2011-2022 走看看