美文网首页
ES6 async 函数

ES6 async 函数

作者: Cherry丶小丸子 | 来源:发表于2024-04-10 15:31 被阅读0次

async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数。当函数执行的时候,一旦遇到 await 就会先返回,等到异步操作完成,再接着执行函数体内后面的语句

async 函数对 Generator 函数的改进,体现在以下四点

(1)内置执行器
(2)更好的语义
(3)更广的适用性
(4)返回值是 Promise

async 函数有多种使用形式
// 函数声明
async function foo() {}

// 函数表达式
const foo = async function () {};

// 对象的方法
let obj = { async foo() {} };
obj.foo().then(...)

// Class 的方法
class Storage {
  constructor() {
    this.cachePromise = caches.open('avatars');
  }

  async getAvatar(name) {
    const cache = await this.cachePromise;
    return cache.match(`/avatars/${name}.jpg`);
  }
}

const storage = new Storage();
storage.getAvatar('jake').then(…);

// 箭头函数
const foo = async () => {};
返回 Promise 对象

async 函数返回一个 Promise 对象
async 函数内部 return 语句返回的值,会成为 then 方法回调函数的参数

async function f() {
    return 'hello world';
}

f().then(v => console.log(v))
// "hello world"

async 函数内部抛出错误,会导致返回的 Promise 对象变为 reject 状态。抛出的错误对象会被 catch 方法回调函数接收到

async function f() {
    throw new Error('出错了');
}

f().then(
    v => console.log('resolve', v),
    e => console.log('reject', e)
)
//reject Error: 出错了
await 命令

正常情况下,await 命令后面是一个 Promise 对象,返回该 Promise 对象的结果。如果不是 Promise 对象,就直接返回对应的值

async function f() {
    // 等同于
    // return 123;
    return await 123;
}

f().then(v => console.log(v))
// 123

await 命令后面的 Promise 对象如果变为 reject 状态,则 reject 的参数会被 catch 方法的回调函数接收到

async function f() {
    await Promise.reject('出错了');
}

f()
.then(v => console.log(v))
.catch(e => console.log(e))
// 出错了

注意,上面代码中,await 语句前面没有 return,但是 reject 方法的参数依然传入了 catch 方法的回调函数。这里如果在 await 前面加上 return,效果是一样的

任何一个 await 语句后面的 Promise 对象变为 reject 状态,那么整个 async 函数都会中断执行

async function f() {
    await Promise.reject('出错了');
    await Promise.resolve('hello world'); // 不会执行
}

有时,我们希望即使前一个异步操作失败,也不要中断后面的异步操作。这时可以将第一个 await 放在 try...catch 结构里面,这样不管这个异步操作是否成功,第二个 await 都会执行

async function f() {
    try {
        await Promise.reject('出错了');
    } catch(e) {

    }
    return await Promise.resolve('hello world');
}

f()
.then(v => console.log(v))
// hello world

另一种方法是 await 后面的 Promise 对象再跟一个 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
使用注意点

第一点,前面已经说过,await 命令后面的 Promise 对象,运行结果可能是 rejected,所以最好把 await 命令放在 try...catch 代码块中

async function myFunction() {
    try {
        await somethingThatReturnsAPromise();
    } catch (err) {
        console.log(err);
    }
}

// 另一种写法

async function myFunction() {
    await somethingThatReturnsAPromise()
    .catch(function (err) {
        console.log(err);
    });
}

第二点,多个 await 命令后面的异步操作,如果不存在继发关系,最好让它们同时触发

let foo = await getFoo();
let bar = await getBar();

上面代码中,getFoo 和 getBar 是两个独立的异步操作(即互不依赖),被写成继发关系。
这样比较耗时,因为只有 getFoo 完成以后,才会执行 getBar,完全可以让它们同时触发

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

// 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;

第三点,await 命令只能用在 async 函数之中,如果用在普通函数,就会报错

async function dbFuc(db) {
    let docs = [{}, {}, {}];

    // 报错
    docs.forEach(function (doc) {
        await db.post(doc);
    });
}

上面代码会报错,因为 await 用在普通函数之中了。但是,如果将 forEach 方法的参数改成 async 函数,也有问题

function dbFuc(db) { //这里不需要 async
    let docs = [{}, {}, {}];

    // 可能得到错误结果
    docs.forEach(async function (doc) {
        await db.post(doc);
    });
}

上面代码可能不会正常工作,原因是这时三个 db.post() 操作将是并发执行,也就是同时执行,而不是继发执行。
正确的写法是采用 for 循环

async function dbFuc(db) {
    let docs = [{}, {}, {}];

    for (let doc of docs) {
        await db.post(doc);
    }
}

第四点,async 函数可以保留运行堆栈

const a = () => {
    b().then(() => c());
};

上面代码中,函数 a 内部运行了一个异步任务 b()。当 b() 运行的时候,函数 a() 不会中断,而是继续执行。
等到 b() 运行结束,可能 a() 早就运行结束了,b() 所在的上下文环境已经消失了。
如果 b() 或 c() 报错,错误堆栈将不包括 a()

现在将这个例子改成 async 函数

const a = async () => {
    await b();
    c();
};

上面代码中,b() 运行的时候,a() 是暂停执行,上下文环境都保存着。一旦 b() 或 c() 报错,错误堆栈将包括a ()

相关文章

  • async await

    文档地址async[http://caibaojian.com/es6/async.html] async函数的语...

  • async/await 整理总结

    参考:红宝书 es6入门 async async 函数的实现原理,就是将 Generator 函数和自动执行器,包...

  • 异步的那些事儿,promise

    promise 是es6 的标准函数,主要是解决执行函数当中的回调问题,相对于async,async只是一套解决回...

  • JS新特性

    ES ES5 ES6 箭头函数 Promise Symbol属性 Iterator Generator async...

  • ES6 知识点整理

    ES6 包括 变量、函数、数组、json、字符串、面向对象、promise、generator、async/awa...

  • 一次性搞懂 Promise、async await 与 Gene

    学习 ES6 的时候,经常听到 Promise、async await 与 Generator 用来处理异步函数,...

  • ES6 async/await关键字 (上)

    async关键字 在ES6中,声明异步函数很简单,只需要在function前加上async关键字即可,如下: 那怎...

  • js异步方法里async await setTimeout

    前言: js异步执行的方法有传统的回调函数callback、es6的promise函数、es7的async awa...

  • ES6 async 函数

    是什么 async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,...

  • Es6 async 函数

    1、 async函数返回一个 Promise 对象。 2、async函数内部抛出错误,会导致返回的 Promise...

网友评论

      本文标题:ES6 async 函数

      本文链接:https://www.haomeiwen.com/subject/tgofxjtx.html