如何从异步函数返回 Promise?

2024-01-08

当我尝试从异步函数返回 Promise 时,无法区分返回的 Promise 和函数的状态。

我认为,最简单的解决方案是将要返回的承诺放在数组中。下面是一个愚蠢的例子,但我希望它能说明问题:

function loadMetaData(id) {/*...*/} // Returns Promise<MetaData>
function loadSingleData(name) {/*...*/} // Returns Promise<SingleData>

async function startLoadingSingleData(id, object) {
    const metaData = object.metaData = await loadMetadata(id);
    const singleDataPromise = loadSingleData(metaData.dataToLoad);
    singleDataPromise.then(metaData => object.metaData = metaData);
    return [singleDataPromise];
}

async function logData(id) {
    const object = new SomeUsefulClassWhatTakesAdvantageOfMetadataProp();
    somePromise = (await startLoadingSingleData(id))[0];
    // Now metadata surely loaded, do something with it
    console.log(object.metaData);
    // But somedata will be loaded only in future
    somePromise.then(singleData => console.log(singleData));

    // And maybe: (depends of use-case)
    await somePromise;
}

执行时logData(/*...*/),首先是metaData短时间后,给定数据的给定 ID,并稍等片刻后,完整的singleData是期待。

但这有点hackish。

克服这种情况的预期方法是什么?

附: 当我尝试返回一个由承诺解决的承诺时,也会出现这个问题。


是的,不幸的是 JS 承诺不是代数的并且你不能用另一个承诺来履行一个承诺 https://stackoverflow.com/q/32168194/1048572。没有办法解决这个问题(除了不使用本机承诺,并且不使用async/await).

最简单和最常见的解决方案确实是使用包装对象。这很自然地解决你的问题:

// takes an id, returns a Promise<{metaData: Data, singleDataPromise: Promise<Data>}>
async function startLoadingSingleData(id) {
    const object = new SomeUsefulClassWhatTakesAdvantageOfMetadataProp();
    object.metaData = await loadMetadata(id);
//                    ^^^^^
    object.singleDataPromise =   loadSingleData(object.metaData.dataToLoad);
//                             ^ no await here
    return object;
}
async function logData(id) {
    const object = await startLoadingSingleData(id));
    // Now metadata surely loaded, do something with it
    console.log(object.metaData);
    // But some singleData will be loaded only in future
    const singleData = await object.singleDataPromise;
    console.log(singleData);
}

请注意,如果您的代码中有异常并且您永远无法处理,这可能会导致未处理拒绝的问题await the singleDataPromise.

(可能更好)的替代方案是重组您的函数,以便您在使用(即等待)它们之前不会创建任何承诺,就像 @Paulpro 也建议的那样。所以你只需编写一个严格顺序的函数

async function logData(id) {
    const object = new SomeUsefulClassWhatTakesAdvantageOfMetadataProp();
    object.metaData = await loadMetadata(id);
    // Now metadata surely loaded, do something with it
    console.log(object.metaData);
    // But some singleData will be loaded only in future
    object.singleData = await loadSingleData(object.metaData.dataToLoad);
    console.log(object.singleData);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何从异步函数返回 Promise? 的相关文章

随机推荐

  • 休眠合并

    我正在测试休眠状态并将此查询提供给 transaction session beginTransaction city new City A city City session merge city city setName B trans
  • 如何禁用/删除离子按钮 Ionic 4 中的离子波纹效果?

    我需要禁用默认设置ion ripple effect在 离子按钮 中
  • 为工作单元上的多个 EF 上下文做准备 - TransactionScope

    我正在考虑实现处理多个数据源的单个工作单元的选项 实体框架 我想出了一个尝试性的方法 现在处理单一上下文 但这显然不是一个好主意 如果我们分析下面的代码 您会认为它是一个糟糕的实现吗 事务范围的生命周期是否是一个潜在问题 当然 如果我们用不
  • Pandas 数据框按多列分组

    给定一个包含两个日期时间列的数据框A and B和一个数字列C 如何分组month两者的A and B and sum C i e In 1 df Out 1 A B C 0 2013 01 01 2013 01 01 0 282863 1
  • 在窗口函数的 FILTER 子句中引用当前行

    In PostgreSQL 9 4窗口函数有一个新选项FILTER选择窗框的子集进行处理 文档提到了它 但没有提供示例 在线搜索产生了一些样本 包括来自第二象限 http blog 2ndquadrant com the within gr
  • 将字符串转换为嵌套列表中的浮点数

    我有一个列表列表 其中包含数字和单词字符串 我只想将那些数字字符串转换为浮点数 aList hi 1 33 bye 1 555 首先 您需要一个函数来执行 如果可能的话将字符串转换为浮点数 否则将其保留为字符串 def floatify s
  • VB.Net 表单非共享方法被引用为共享方法?

    尽管我主要是一名 C 开发人员 但我正在为 VB Net 应用程序提供支持 我遇到过我认为 奇怪 的代码 因为我的 C 思维方式告诉我该代码是错误的 不应该编译 但它确实编译了 我做了一个查找所有参考文献在特定的表单上查看它的使用位置 并找
  • 母版页和视图中的表单

    我有一个母版页 我的所有视图都继承自该母版页 我遇到的问题是在母版页中创建的表单标签 然后是在视图中创建的表单标签 由于表单位于母版页表单内 因此我的所有回发都会发送到控制器 Index 方法 这迫使我创建一个新方法 Index 来强制使用
  • 如何在 Ruby 中取消类的定义?

    在 Ruby 中取消定义方法非常简单 我可以使用undef METHOD NAME 有类似的班级吗 我在MRI 1 9 2 我必须取消定义 ActiveRecord 模型 运行两行代码 然后将模型恢复到其原始形式 问题是 我有一个模型Con
  • 为什么派生类属性值在基类构造函数中看不到?

    我写了一些代码 class Base Default value myColor blue constructor console log this myColor class Derived extends Base myColor re
  • 组合扩展器和网格(可调整大小的扩展器)

    我想要一个类似可调整大小的扩展器之类的东西 我的基本想法是这样的
  • Python 3.x 导入错误 SyntaxError [重复]

    这个问题在这里已经有答案了 我正在使用 macOS Sierra 导入时builtwith我收到以下错误 Daniels MacBook Pro Daniel python Python 3 5 2 Anaconda 4 2 0 x86 6
  • ImportError:无法导入名称“_ColumnEntity”Ubuntu20.10 [重复]

    这个问题在这里已经有答案了 pip install apache superset 然后我写了 superset db upgrade 我收到以下错误 Traceback most recent call last File home co
  • 在大型数据表中替换 NA 的最快方法

    我有一个大数据表 http cran r project org web packages data table index html 许多缺失值分散在大约 20 万行和 200 列中 我想尽可能有效地将这些 NA 值重新编码为零 我看到两
  • 如何在 Laravel 中验证 API 路由的 Vue.js / Axios 请求

    我在 Laravel 5 6 中 我已经构建了所有 API 路由 并正确响应来自 REST 客户端 Paw 的请求 我正在尝试构建一个简单的前端来访问这些路由 我尝试尽可能多地使用 Laravel 的开箱即用功能 因此我使用 Axios 使
  • 多次 fork 调用会导致 BlockingIOError

    我正在寻找有关以下代码片段的错误的解释 usr bin env python3 import os sys if name main while True pid os fork if pid 0 sys exit elif pid gt
  • 在 Entity Framework Core 中获取当前用户 ID 的正确方法

    对于 ASP NET Core 的不同 RC 关于如何获取当前登录用户的 ID 这里有很多不同的答案 我想在这里问一个明确的问题 请注意 project json 现在有 Microsoft AspNetCore Identity Enti
  • 相当于 grails 中的 InheritanceType.TABLE_PER_CLASS 吗?

    我想为 3 个域类创建 3 个单独的表 A B 扩展 A C 扩展 B 但我希望他们的表不相互连接 在hibernate中 我会使用InheritanceType TABLE PER CLASS 在grails中 等价物是什么 尝试使用ta
  • Golang 结构体接口

    我有一个函数 其参数类型为 interface 如下所示 func LoadTemplate templateData interface 就我而言 templateData 是一个结构 但每次它都有不同的结构 我使用 interface
  • 如何从异步函数返回 Promise?

    当我尝试从异步函数返回 Promise 时 无法区分返回的 Promise 和函数的状态 我认为 最简单的解决方案是将要返回的承诺放在数组中 下面是一个愚蠢的例子 但我希望它能说明问题 function loadMetaData id Re