Асинхронная функциональность в функции наблюдения - PullRequest
0 голосов
/ 27 февраля 2019

Что ж, у меня есть следующий код, который , по-видимому, хорошо работает:

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) Невозможно вызвать observeс асинхронной функцией, связанной с listener, поскольку Promise [1] несовместимо с неопределенным [2] в возвращаемом значении.

Глядя на mobx.js.flow Я действительно вижу, что он всегда принимаетпростая функция, возвращающая void.документация молчит по этому вопросу.Так может ли наблюдатель принять функцию обещания (асинхронную) внутри нее?- Является ли это «ошибкой» при наборе.
Или я неправильно использую наблюдатель, и мне просто «повезло», что функция в конечном итоге будет выполнена?

Если кто-то не может этого сделать, чтолучший способ переписать это?В конце концов мне нужно позвонить this.reloadEntries(), который возвращает обещание / делает звонок на сервер, при смене пользователя.

1 Ответ

0 голосов
/ 27 февраля 2019

Итак, сигнатура для аргумента слушателя этой функции observe в mobx:

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

Соответствующий бит - это тип возвращаемого значения void, который указывает, что функция должна быть толькоспособен возвращать undefined (или неявно только возвращать undefined, не имея оператора return).

Асинхронные функции всегда возвращают Promise.Механизм того, как выполняется преобразование async / await и как выглядит результирующий код, хорошо объяснен в спецификации , но достаточно сказать, что ваш код фактически заменяется кодом, который всегда будет возвращать Promise.

Короткий ответ - просто не передавать асинхронную функцию там, где ее не ожидают.Вот некоторые варианты:

  1. Переработать функцию, чтобы просто вызвать then вместо того, чтобы полагаться на await.Возможно, самый чистый вариант в этом случае.
  2. Превратите вашу асинхронную функцию во IIFE: ((...args) => { (async (...) {...})(...args) }
  3. Повторно введите вашу функцию, набрав any: ((myListener): any): (MyArgTypes) => void) (несделать это)
  4. Использовать комментарий $FlowFixMe (не делайте этого тоже)

Итак, почему это работает?

Потому что mobx ожидает функцию, которая возвращает только void, потому что она не собирается ничего делать с любым возвращаемым значением.Он не запрашивает возвращаемое значение, потому что не собирается использовать его.Ваше возвращаемое значение, Promise, просто отбрасывается mobx.Таким образом, он продолжит работать так же, как и всегда, несмотря на эту ошибку типа.

Почему MOBX не может просто ввести возвращаемое значение как any?В конце концов, mobx не волнует, что вы возвращаете.

Потому что это было бы плохим дизайном API и внесло бы опасную скользкость при наборе текста.API нужен надежный, разумный контракт.Что если пользователь передаст observe a listener, который вернул результат, потому что он ошибочно полагал, что mobx действительно сделает что-то с этим результатом?Или что, если пользователь, например, передал функцию более высокого порядка вместо возвращаемого значения этой функции более высокого порядка?Обе эти ошибки не будут обнаружены менее строгим типом в этой позиции.

Почему асинхронная функция всегда возвращает Promise, даже если я все равно ее просто отбрасываю?

Хотя возвращение Promise в зависимости от использования может быть записано в спецификации , или, возможно, передать какую-то опцию, чтобы не возвращать Promise, вполне вероятно, чтов результате сложился с очень небольшим вознаграждением.Цель спецификации async / await - получить максимально возможную полезность, не добавляя слишком много сложности.Многие, но не все, асинхронные функции используются в сильно асинхронных кодовых базах, где возвращение Promise будет лучшей идеей, чем нет.Кроме того, после того, как функция была объявлена ​​асинхронной, невозможно безопасно возвращать значение из другого, кроме как асинхронным способом (Promise), без каких-либо копаний в теле функции и попытки определить использование.

...