• ES6 异步编程解决方案 之 Async


    一、async 函数的基本用法

    • async 函数返回一个 Promise 对象,可以使用 thencatch 方法 添加回调函数

    • async 函数执行时,一旦遇到 await 就会先返回,等到异步操作完成,再接着执行函数体内后面的语句 【异步函数 同步执行】

    • async 函数有很多种形式:

    // 函数声明
    async function foo() {}
    
    // 函数表达式
    const foo = async function () {};
    
    // 箭头函数
    const foo = async () => {};
    
    // Class 的方法
    class Storage {
      constructor() {
        this.cachePromise = caches.open('avatars');
      }
    
      async getAvatar(name) {
        const cache = await this.cachePromise;
        return cache.match(`/avatars/${name}.jpg`);
      }
    }
    
    // 对象的方法
    let obj = { async foo() {} };
    obj.foo().then(...)
    
    • 示例: 指定多少毫秒后输出一个值
    function timeout(ms) {
        return new Promise((resolve) => {
            setTimeout(resolve, ms);
        });
    }
    
    async function asyncPrint(value, ms) {
        await timeout(ms);
        console.log(value);
    }
    
    asyncPrint('hello world', 50);
    
    // 上面代码指定 50 毫秒以后,输出 hello world
    

    二、async 语法

    1. async 函数

    • async 函数的返回值 是 Promise 对象 (可调用 thencatch 方法)

    • async 函数内部抛出错误,会导致返回的 Promise 对象变为 reject 状态

    • async 函数的回调方法 thencatch 的参数

      • async 函数内部 return 关键字返回的值,会 作为 thencatch 方法的参数

      • async 函数的返回的 Promise 对象 状态为 resolve 时,函数内部 若没有返回值,thencatch 方法的参数 为 undefined;调用 then 方法

      • async 函数的返回的 Promise 对象 状态为 reject 时,函数内部 若没有返回值,thencatch 方法的参数 为 错误对象;调用 catch 方法

    async function f() {
        return await Promise.resolve(123);
    }
    
    f().then(v => console.log(v));  // 123
    
    async function f() {
        await Promise.resolve(123);
    }
    
    f().then(v => console.log(v));  // undefined
    
    async function f() {
      throw new Error('出错了');
    }
    
    f().then(
      v => console.log(v),
      e => console.log(e)   
    )   // Error: 出错了
    

    2. await 关键字

    • await 关键字 只能在 async 函数中使用: await 后面 如果跟异步函数,程序执行时会等 await 后面的 异步函数执行完之后,再执行 后面的代码 【异步函数 同步执行】

    • 正常情况下,await 命令后面是一个 Promise 对象;如果不是,会转成 Promise 对象,并立即 resolve

    // 只要有一个 `await` 后面的函数执行错误,程序就会停止执行代码
    
    async function f() {
        await Promise.reject('出错了');
        await Promise.resolve('hello world'); // 不会执行
    }
        
    f().then(
        (result) => {
            console.log(result);
        },
        (e) => {
            console.log(e);     
        }
    );      // 出错了
    

    三、async 应用

    1. 一个 async 函数中,有多个 await 关键字:使用 try..catch( ) 避免程序终止

    • 场景: 只要有一个 await 后面的函数执行错误,程序就会停止执行代码; async 函数返回的 Promise 对象的状态为 reject

    • 解决方案:

      • 方案 1:使用 try...catch() 把有可能出错的 操作放到 try 语句中

      • 方案 2:await 后面的 Promise 对象再跟一个 catch 方法,处理前面可能出现的错误

    // 解决方案 1:try...catch() 即使有一个异步操作失败,也不终止程序
    
    async function f() {
        try {
            await Promise.reject('出错了');
        } catch(e) {
            console.log(e);
        }
        
        return await Promise.resolve('hello world');
    }
    
    f().then(v => console.log(v))
    // hello world
    
    // 解决方案 2:catch() 即使有一个异步操作失败,也不终止程序
    
    async function f() {
        await Promise.reject('出错了')
            .catch(e => console.log(e));
        return await Promise.resolve('hello world');
    }
    
    f().then(v => console.log(v))
    // 出错了
    // hello world
    

    2. 一个 async 函数中,有多个 await 关键字:使 await 后面的异步操作 同时执行

    // 写法一
    let [foo, bar] = await Promise.all([getFoo(), getBar()]);
    
    // 写法二
    let fooPromise = getFoo();
    let barPromise = getBar();
    let foo = await fooPromise;
    let bar = await barPromise;
    

    3. 使用 try...catch() 结合 asyncawait 实现 ajax 请求轮询

    const NUM_RETRIES = 3;
    
    async function ajaxRequest() {
        for (let i = 0; i < NUM_RETRIES; ++i) {
            try {
                await $.get('http://google.com/this-throws-an-error');
                break;
            } catch(err) {
                console.log(err);
            }
        }
    }
    
    ajaxRequest();
    

    四、async for await...of ---> 异步遍历

    • 遍历时,有一个异步请求报错,都会导致程序终止;所以,结合 try...catch() 解决此类问题
    async function () {
        try {
            for await (const x of createRejectingIterable()) {
                console.log(x);
            }
        }
        catch (e) {
            console.error(e);
        }
    }
    

    五、async 与 其他异步解决方案的 比较

    • Promise: 比回调函数的写法大大改进,但是一眼看上去,代码完全都是 Promise 的 API(then、catch等等),操作本身的语义反而不容易看出来

    • Generator: 语义比 Promise 写法更清晰,需要有 任务运行器,自动执行 Generator 函数;但偏底层的写法

    • async: Generator 函数的语法糖,封装了 Generator 的底层机制 ,实现最简洁,最符合语义;

  • 相关阅读:
    WCF进行大数据传输时的相关配置(转)
    自定义绑定(转)
    菜鸟学TSQLSQL2005读书笔记1
    再别康桥英文及译文
    自定义绑定2
    我要读的书
    菜鸟学TSQLSQL2005读书笔记
    Bad Habbits
    实践测试驱动开发
    针对接口写测试用例
  • 原文地址:https://www.cnblogs.com/zxvictory/p/8548443.html
Copyright © 2020-2023  润新知