【问题标题】:Asynchronous functionality in "observe" function“观察”功能中的异步功能
【发布时间】:2019-02-27 22:46:07
【问题描述】:

我有以下代码,似乎运行良好:

observe(
    store, "user",
    async (data: {oldValue: ?UserTy, newValue: ?UserTy}) => {
        const {oldValue: previousUser, newValue: newUser} = data;

        this.entries = [];
        this.confirmed_entries = [];
        this.paid_entries = [];
        if (newUser) {
            const clear = !!previousUser;
            await this.reloadEntries(clear);
        }
        this.last_reload = new Date();
    }
);

在用户更改(登录/注销)时,这将重新加载(从数据库)当前用户的“条目”。

现在我将流添加到混合中,突然出现以下错误:

错误:(47, 64) 无法使用绑定到listener 的异步函数调用observe,因为Promise [1] 与返回值中未定义的[2] 不兼容。

查看mobx.js.flow,我确实可以看到它总是接受一个简单的函数,返回void。关于这个问题的文档是silent。那么观察者可以接受它里面的promise(异步)函数吗? -- 这是打字的“错误”吗?
或者我是否使用了错误的观察者,我只是“幸运地”最终执行了该函数?

如果无法做到这一点,那么重写它的最佳方法是什么?最后,我需要调用this.reloadEntries(),它会在用户更改时返回一个承诺/调用服务器。

【问题讨论】:

    标签: javascript asynchronous flowtype mobx


    【解决方案1】:

    所以,这个 observe 函数在 mobx 中的 listener 参数的签名是:

    listener: (change: IMapChange<K, T>) => void,
    

    相关位是返回类型void,它表示函数应该只能返回undefined(或者通过没有返回语句隐式地只返回undefined)。

    异步函数总是返回Promisethe spec 很好地解释了如何执行 async/await 转换的机制以及结果代码的外观,但只要说您的代码有效地替换为始终返回 Promise 的代码就足够了。

    简短的回答是不要在不期望的地方传递异步函数。以下是一些选项:

    1. 重做函数,只调用then,而不是依赖await。在这种情况下,这可能是最干净的选择。
    2. 把你的异步函数变成一个 IIFE:((...args) =&gt; { (async (...) {...})(...args) }
    3. 通过键入any 重新键入您的函数:((myListener): any): (MyArgTypes) =&gt; void)(不要这样做)
    4. 使用$FlowFixMe 评论(也不要这样做)

    那么,为什么它起作用了?

    因为 mobx 期望一个只返回 void 的函数,因为它不会对任何返回值做任何事情。它不要求返回值,因为它不会使用一个。你的返回值,Promise,只是被 mobx 丢弃了。因此,尽管出现这种类型错误,它仍会像往常一样继续工作。

    为什么 mobx 不直接将返回值键入为any?毕竟,mobx 不在乎你返回什么。

    因为这将是糟糕的 API 设计,并在键入时引入危险的滑溜。 API 需要一个可靠、合理的合约。如果用户传递observe 和返回结果的listener 会怎样,因为他们误以为mobx 实际上会 对这个结果做些什么?或者,例如,如果用户传入了一个高阶函数而不是该高阶函数的返回值,该怎么办?这两个错误都不会被这个位置的不太严格的类型捕获。

    为什么异步函数总是返回 Promise,即使我还是要丢弃它?

    虽然仅根据用法返回Promise可能已写入规范,或者可能传递某种选项以不返回Promise,但它的复杂性可能会激增结果奖励很少。 async/await 规范的目标是在不增加太多复杂性的情况下获得最大可能的实用性。许多(但不是全部)异步函数正在高度异步的代码库中使用,其中返回 Promise 会是一个更好的主意。此外,一旦函数被声明为异步,除了以异步方式(Promise)之外,没有其他方法可以安全地从函数返回值,除非以某种方式深入函数体并尝试确定用法。

    【讨论】:

    • 感谢您的长回答,但是 mobx 开发人员不支持/维护打字,所以我不能“信任”它。重新使用 "then .. else" 有完全相同的实际问题:mobx 是否等待 promise 完成?
    • 选项 2 肯定会破坏一切:永远不会等待异步函数,因此您不再确定该函数会执行......永远。
    • Mobx 在您的示例中不会等待承诺完成。如果你不信任流类型,那 mobx 的 TypeScript 源码呢? Here 是 TS 中对应的类型,你会注意到它基本上是一模一样的,here 是监听器被调用的地方,你会注意到返回值被丢弃了。
    猜你喜欢
    • 2019-01-11
    • 2016-11-28
    • 1970-01-01
    • 2021-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多