博客
关于我
Promise及Es6Async Await 如何异常捕获?
阅读量:734 次
发布时间:2019-03-21

本文共 4801 字,大约阅读时间需要 16 分钟。

Promise和Async Await的异常捕获之旅

本篇文章或许已经介绍过Promise和Async Await的基础知识,今文将深入探讨它们如何处理异常。这是特别关注点,也是开发者在使用这些特性时容易忽视的一部分。

一、Promise的异常捕获

Promise提供了两个主要方法来处理异常:.then()和.catch()。

  • 通过.then()的第二个参数捕获异常

    .then()方法接受两个参数:第一个是成功回调函数,第二个是失败回调函数。可以利用第二个参数来捕获异常。例如:

    let promise = new Promise((resolve, reject) => {    reject('错误');});promise.then(() => {}, (error) => {    console.log(error); // '错误'});
  • 通过.catch()捕获异常

    .catch()方法是一个更简便的方式来捕获所有异常。它内部会调用 Promise.prototype.then(undefined, onRejected),因此可以直接用于处理失败情况:

    let promise = new Promise((resolve, reject) => {    reject('错误');});promise.catch((error) => {    console.log(error); // '错误'});
  • 通过链式编写了解两者的差异

    有时候项目会采用链式编写方式,可以通过实验发现,.then()的第二个参数和.catch()存在优先级问题。由于.then()的第二个参数会返回一个新 Promise,后续的.catch()可能不会捕获前面的错误。例如:

    let promise = new Promise((resolve, reject) => {    reject('失败');});promise.then(() => {}, (err) => {}).catch((err) => {    console.log(err); // 这里不会执行});

    相反,如果替换.then()的第二个参数为一个返回值,则后面的.catch()可能无法捕获早期错误:

    let promise = new Promise((resolve, reject) => {    reject('失败');});promise.then(() => {}, (err1) => {    return promise1; // 注意:假设 promise1 是关于同一 Promise}).then(() => {}).catch((err2) => {    console.log(err2); // ReferenceError: promise1 未定义});

    由此可见,.catch()适用于整个链式结构的错误捕获,而 .then()的第二个参数仅捕获前一个 Promise 的结果。

  • 错误传播的优先级规则

    如果你在.then()的第二个参数中返回一个新的 Promise 或直接调用 .catch(),错误传播的规则会发生改变。例如:

    let promise = new Promise((resolve, reject) => {    reject('失败');});promise.then(() => {}, (err1) => {    return new Promise((resolve, reject) => {        reject('后续错误');    });}).then(() => {}, (err2) => {    console.log(err2); // ReferenceError: promise1 未定义});

    这里的瓶颈在于,.then()的链式结构会导致错误被传递到后续链路,而如果我们使用.catch(),则可以捕获整个链路上的所有错误:

    let promise = new Promise((resolve, reject) => {    reject('失败');});promise.then(() => {}, (err1) => {}).catch((err2) => {    console.log(err2); // '失败'});
  • 避免迷失:正确使用 catch 的方法

    它被建议在多层次的 Promise 链式结构中使用.catch()来捕获所有错误,而不是在每一个.then()中都手动添加一个失败回调。这使得代码更加简洁且易于阅读:

    let promise = new Promise((resolve, reject) => {    reject('失败');});promise.then(() => {}).catch((err) => {    console.log('失败'); // 这里会执行});

    这样的结构会更关注程序的主要逻辑,而不是繁琐的错误处理逻辑。

  • Promise.value穿透(Promises 的值穿透)

    值穿透是指在 Promise 链式执行中,将非函数值通过链式传递下去。例如:

    Promise.resolve(1).then(2).then(() => {    console.log(1);});

    在这个例子中,2 会被作为参数传递给链式的下一个.then(),但不会被阻止,因为它不是一个函数。这类行为可以帮助简化代码,但可能会引发一些潜在的问题。

    例如:

    Promise.resolve(1).then(2).then(() => {    console.log(2);});

    这里,2 会被直接传递给 then 的第一个参数,因为它不是一个函数,导致将 2 作为状态处理。为了ulse)的错误传播方式。

  • 二、Async Await的异常捕获

    Async 函数需要结合 await 关键字来进行异步操作和错误处理。与 Promise 不同,async 函数允许我们将多个异步操作串联起来,同时在严格的同步代码中处理。此外,async 函数内可以使用 try...catch 进行错误捕获。

  • 在外部捕捉 async 函数的错误

    async 函数返回的是一个 Promise,所有的错误都会被Promise 接收,然后可以在外部通过 catch 来捕获:

    async function test() {    await new Promise((resolve, reject) => {        reject('错误');    });}test().catch((data) => {    console.log(data); // '错误'});
  • 在 async 函数内部捕捉错误

    如果需要在 async 函数内部处理错误,可以使用 try...catch 实现:

    async function test() {    try {        await new Promise((resolve, reject) => {            reject('错误');        });    } catch (error) {        console.log('错误发生在内部', error);    }}test();
  • await 后接 catch 捕捉错误

    await 错误同样可以被传递到 catch 中:

    async function test() {    await new Promise((resolve, reject) => {        reject('错误');    }).catch((data) => {        console.log('错误From await', data);    });    await new Promise((resolve, reject) => {        reject('错误1');    }).catch((data) => {        console.log('错误从await的另一个错误1', data);    });    await new Promise((resolve, reject) => {        reject('错误2');    }).catch((data) => {        console.log('错误从 await,错误2’, data);    });}test();
  • 优化代码:封装错误处理

    有时候,在多个地方重复操作相同的错误处理逻辑,可以封装到一个函数中:

    const promiseValue = (promise) => {    return promise.then((data) => [null, data]).catch((err) => [err]);};async function test() {    let [err, data] = await promiseValue(new Promise((resolve, reject) => {        reject('错误');    }));    if (err) {        console.log('错误发生在这里');    }    let [err1, data1] = await promiseValue(new Promise((resolve, reject) => {        reject('错误1');    }));    if (err1) {        console.log('错误1发生在这里');    }    let [err2, data2] = await promiseValue(new Promise((resolve, reject) => {        reject('错误2');    }));    if (err2) {        console.log('错误2发生在这里');    }}test();

    这种封装不仅提高了代码的可读性,还减少了重复代码。

  • 三、比较和总结

    通过对 Promise 和 Async Await 的错误处理机制的比较,可以得出以下结论:

    • 优先级和顺序:在链式结构中,.catch() 方法返回一个新的 Promise,其优先级高于 .then() 的第二个参数。因此,后面的链式操作可能会影响前面的错误传递。

    • 错误处理的位置:及时使用 try...catch 语句能够更好地控制异常,避免在多层面的回调中迷失。这是因为 async 函数允许你在同一代码块内处理所有的异步操作和错误。

    • value 穿透:在 Promise 链式结构中,非函数值会自动传递下去,这可以简化代码,但在处理错误时可能会引发一些意想不到的问题。

    • 选择的最佳方式:在实际开发中,可以根据项目需求和具体场景灵活选择。这可能包括使用默认的 .catch() 还是在 .then() 中手动捕获错误,这取决于你需要处理的层级和结构。

    • 综合考虑:无论选择哪种方式,代码的清晰度和可读性都是关键。因此,合理拆分代码,使用适当的错误处理逻辑,可以使整个应用更加健壮和高效。

    通过深入理解和正确运用 Promise 和 Async Await 的异常捕获机制,我们可以更好地管理异步代码,确保程序的高效运行和错误的顺利处理。这个知识点对于开发高质量的现代 web 应用至关重要。

    转载地址:http://qumgz.baihongyu.com/

    你可能感兴趣的文章
    mysql 快速自增假数据, 新增假数据,mysql自增假数据
    查看>>
    Mysql 报错 Field 'id' doesn't have a default value
    查看>>
    MySQL 报错:Duplicate entry 'xxx' for key 'UNIQ_XXXX'
    查看>>
    Mysql 拼接多个字段作为查询条件查询方法
    查看>>
    mysql 排序id_mysql如何按特定id排序
    查看>>
    Mysql 提示:Communication link failure
    查看>>
    mysql 插入是否成功_PDO mysql:如何知道插入是否成功
    查看>>
    Mysql 数据库InnoDB存储引擎中主要组件的刷新清理条件:脏页、RedoLog重做日志、Insert Buffer或ChangeBuffer、Undo Log
    查看>>
    mysql 数据库备份及ibdata1的瘦身
    查看>>
    MySQL 数据库备份种类以及常用备份工具汇总
    查看>>
    mysql 数据库存储引擎怎么选择?快来看看性能测试吧
    查看>>
    MySQL 数据库操作指南:学习如何使用 Python 进行增删改查操作
    查看>>
    MySQL 数据库的高可用性分析
    查看>>
    MySQL 数据库设计总结
    查看>>
    Mysql 数据库重置ID排序
    查看>>
    Mysql 数据类型一日期
    查看>>
    MySQL 数据类型和属性
    查看>>
    mysql 敲错命令 想取消怎么办?
    查看>>
    Mysql 整形列的字节与存储范围
    查看>>
    mysql 断电数据损坏,无法启动
    查看>>