当前位置: 首页 > 知识库问答 >
问题:

promise - 哪些场景下使用await/async更好?哪些场景下使用then更好?

慕震博
2024-07-04

哪些场景下使用await/async更好?哪些场景下使用then更好?

我的认为await/async的出现是为了改善then的使用,当比较复杂的时候,await/async会起到作用,当问题比较简单的时候用then。但是我们还是应该选择其中一种,这样代码风格比较统一。

例如我下面这个需求使用的await/async不知道是否合适(是不是变得麻烦了?)
工作1:获得选择列表,并默认选择全部。
工作2:根据选择的单位和其他信息向服务端发送请求,获取数据之后根据数据刷新页面

当初始加载该页面的时候,整合工作1和工作2。

async function getDwSelections() {
  try {
    const result = await getDwList();
    if (!result.isSucceed) throw new Error("获取单位列表失败,错误信息:' + result.errMsg")
    const data = result.data[0].datas
    console.log("dw selections: ", data);
    dwSelections.value.push({
      value: "全部",
      label: "全部"
    })
    for (const item of data) {
      dwSelections.value.push({
        value: item.dwdm,
        label: item.dwmc
      })
    }
    selectedDw.value = "全部";
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : error;
    throw new Error(errorMessage);
  }
}
async function query() {
  try {
    const result = await getTableData({dwdm: selectedDw.value === "全部" ? '' : selectedDw.value, ny: selectedDate.value})
    if (!result.isSucceed) throw new Error("获取数据失败,错误信息:" + result.errMsg)
    rqToDm.value = {};
    const data = result.data[0].datas;
    const newTableData = new Map();
    const newDateFields = new Set();
    const currentDate = common.getCurrentDate("yyyy-MM-dd");
    for (const entry of data) {
     if(entry.rqdm > currentDate) continue;
      if (newTableData.has(entry.jlid)) {
        newTableData.get(entry.jlid)[entry.rq] = entry.rjql;
      } else {
        newTableData.set(entry.jlid, {
          jlid: entry.jlid,
          ny: selectedDate.value,
          dwmc: entry.dwmc,
          jqd: entry.jqd,
          dlgs: entry.dlgs,
          jqfs: entry.jqfs,
          ljjql: entry.ljjql,
          rpjql: entry.rpjql,
          ljdsl: entry.ljdsl,
          [entry.rq]: entry.rjql
        })
      }
      newDateFields.add(entry.rq)
      rqToDm.value[entry.rq] = entry.rqdm;
    }
    dateFields.value = Array.from(newDateFields).map(e => {
      return {"label": e, "prop": e};
    });
    tableData.value = Array.from(newTableData.values());

  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : error;
    throw new Error(errorMessage);
  }
}
onMounted(async () => {
  loading.value = true;
  try {
    await getDwSelections();
    await query()
  } catch (error) {
    ElMessage.error(error.message);
  }
  loading.value = false;
})

附:代码中有什么其他问题也欢迎指正。

共有2个答案

李博达
2024-07-04
  1. 顺序执行,后面的环节依赖前面的结果,用 await
  2. 支线执行,不影响主线,用 .then,比如数据埋点
  3. 需要跨文件等待执行结束,return new Promise
凌蕴藉
2024-07-04

使用await/async的场景

  • 当需要按照顺序执行多个异步操作时,await/async 提供了更清晰的控制流,使得代码看起来像同步代码一样,易于理解和维护。
  • 在需要等待异步操作结果,并且基于该结果执行后续操作时,await/async 是很好的选择。
  • 当需要在异步函数中使用try...catch来捕获错误时,await/async 是唯一的选择,因为then的链式调用中捕获错误通常需要使用额外的.catch()方法。
  • 在处理嵌套异步调用时,await/async 可以避免回调地狱(Callback Hell),使得代码更加简洁和可读。

在你的例子中,使用await/async是合适的,因为你需要按顺序执行getDwSelectionsquery函数,并且基于这些函数的结果来更新页面。

使用then的场景

  • 当不需要等待异步操作的结果,或者不需要基于该结果执行后续操作时,可以使用.then()
  • 在某些老旧的代码库或特定的编程风格中,可能更倾向于使用.then()来处理异步操作。
  • 当需要并行执行多个异步操作,并且不关心它们的完成顺序时,可以使用Promise.all().then()结合来同时处理所有操作的结果。

你的代码中的问题

你的代码在逻辑上是清晰的,使用了await/async来按顺序执行异步操作,并使用了try...catch来捕获错误。不过,有一些小的改进点:

  1. 错误处理:在catch块中,你重新抛出了一个错误。虽然这没有问题,但如果你只是想记录错误而不希望中断程序流程(比如,在开发环境中),你可能只是想要打印或记录错误,而不是重新抛出它。
  2. 错误消息:在throw new Error中,字符串拼接有误。你使用了单引号包围了字符串字面量,但忘记了在+操作符之后添加单引号来继续字符串字面量。应该修改为:

    throw new Error("获取单位列表失败,错误信息:" + result.errMsg);
  3. 代码复用:在query函数中,错误处理部分与getDwSelections中的类似。如果这种错误处理逻辑在多个地方都有使用,可以考虑将其封装为一个单独的函数或方法。
  4. 状态管理:你的代码中使用了多个全局变量(如dwSelections.valueselectedDw.value等)来管理状态。虽然这在Vue这样的框架中是常见的,但确保这些变量在组件的适当范围内被正确初始化和管理是很重要的。
  5. 代码组织:考虑将getDwSelectionsquery函数组织到一个更具体的模块或服务中,以便在其他地方重用这些逻辑。
  6. 代码可读性:函数和变量名应该清晰明了,反映它们的用途。例如,rqToDm.valuedateFields.value这样的变量名可能需要一些上下文才能理解其含义。如果可能的话,使用更具描述性的名称可以提高代码的可读性。
 类似资料:
  • 本文向大家介绍iframe的使用场景有哪些?相关面试题,主要包含被问及iframe的使用场景有哪些?时的应答技巧和注意事项,需要的朋友参考一下 1:典型系统结构,左侧是功能树,右侧就是一些常见的table或者表单之类的。为了每一个功能,单独分离出来,采用iframe。  2:ajax上传文件。  3:加载别的网站内容,例如google广告,网站流量分析。 4: 在上传图片时,不用flash实现无刷

  • Redis是基于内存的nosql数据库,可以通过新建线程的形式进行持久化,不影响Redis单线程的读写操作 通过list取最新的N条数据 模拟类似于token这种需要设置过期时间的场景 发布订阅消息系统 定时器、计数器

  • 1、解决异步问题 例如用户注册,发送邮件和短信反馈注册成功,可以使用RabbitMQ消息队列,用户无需等待反馈。 2、服务间解耦 订单系统和库存系统,中间加入RabbitMQ消息队列,当库存系统出现问题时,订单系统依旧能正常使用,降低服务间耦合度。 3、秒杀系统 利用RabbitMQ的最大值,实现秒杀系统。

  • 本文向大家介绍RabbitMQ 的使用场景有哪些?相关面试题,主要包含被问及RabbitMQ 的使用场景有哪些?时的应答技巧和注意事项,需要的朋友参考一下 抢购活动,削峰填谷,防止系统崩塌。 延迟信息处理,比如 10 分钟之后给下单未付款的用户发送邮件提醒。 解耦系统,对于新增的功能可以单独写模块扩展,比如用户确认评价之后,新增了给用户返积分的功能,这个时候不用在业务代码里添加新增积分的功能,只需

  • 本文向大家介绍v-once的使用场景有哪些?相关面试题,主要包含被问及v-once的使用场景有哪些?时的应答技巧和注意事项,需要的朋友参考一下 v-once 只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。

  • MySQL 是目前世界上最流行的开源关系数据库,大多应用于互联网行业。比如,在国内,大家所熟知的百度、腾讯、淘宝、京东、网易、新浪等,国外的 Google、Facebook、Twitter、GitHub 等都在使用 MySQL。社交、电商、游戏的核心存储往往也是 MySQL。 任何产品都不可能是万能的,也不可能适用于所有的应用场景。那么 MySQL 到底适用于哪些场景又不适用于哪些场景呢? 1.

  • 本文向大家介绍margin和padding使用的场景有哪些?相关面试题,主要包含被问及margin和padding使用的场景有哪些?时的应答技巧和注意事项,需要的朋友参考一下 margin:      需要在border外侧添加空白时;      空白处不需要背景(色)时;     上下相连的两个盒子之间的空白,需要相互抵消时。 padding:     需要在border内测添加空白时;    

  • ThreadLocal 是一个本地线程副本变量工具类,在每个线程中都创建了一个 ThreadLocalMap 对象,简单说 ThreadLocal 就是一种以空间换时间的做法,每个线程可以访问自己内部 ThreadLocalMap 对象内的 value。通过这种方式,避免资源在多线程间共享。 原理:线程局部变量是局限于线程内部的变量,属于线程自身所有,不在多个线程间共享。Java提供ThreadL