Основы MobX

внешний интерфейс React.js MobX Ember.js

Эта статья написана автором MobX Мишелем Вестстратом, оригинал: https://hackernoon.com/the-fundamental-principles-behind-mobx-7a725f71f3e8.

недавноBertalan MiklosНаписал хороший пост в блоге, в котором сравнил MobX и NX-фреймворк на основе прокси. Этот пост в блоге не только демонстрирует жизнеспособность прокси, но еще лучше то, что он затрагивает некоторые очень простые, но часто скрытые концепции MobX. До сих пор я не останавливался на этих концепциях, поэтому в этой статье я расскажу об умственном путешествии по некоторым функциям MobX.

Почему MobX запускает все форки синхронно

В этой статье затрагивается очень важная особенность MobX (ИМХО): в MobX все производные запускаются синхронно. Это довольно необычно, потому что большинство UI-фреймворков не делают этого, если они также разветвляются (реактивные/потоковые библиотеки, такие как RxJS, также работают синхронно по умолчанию, но им не хватает прозрачного отслеживания, так что это не совсем истинная сопоставимость).

Перед разработкой MobX я потратил некоторое время на изучение того, как разработчики рассматривают существующие библиотеки. Такие фреймворки, как Meteor, Knockout, Angular, Ember и Vue, демонстрируют такое же реактивное поведение, как и MobX, и все они существуют уже давно. Так почему я создаю MobX? Покопавшись в недовольных проблемах и комментариях людей об этих библиотеках, я нашел повторяющуюся тему, которая создала разрыв между тем, что можно ожидать от реактивного, и ужасными проблемами, с которыми приходится иметь дело на практике.

Эта повторяющаяся тема — «предсказуемость». Отладка становится сложной, если фреймворк запускает ваш код дважды или с задержкой. Или может случиться так, что даже «простые» абстракции, такие как промисы, как известно, трудно отлаживать из-за присущей им асинхронной природы.

Я согласен с тем, что непредсказуемость существует, что вполне нормально, и одна из наиболее важных причин популярности шаблона Flux, особенно Redux, заключается в том, что он точно справляется с проблемами предсказуемости в масштабе, в дополнение к тому, что в нем нет ничего волшебного.

MobX использует другой подход: вместо того, чтобы придерживаться всей концепции автоматизированных функций трассировки и запуска, попытайтесь найти основную проблему, чтобы мы всегда могли извлечь выгоду из этого шаблона. Прозрачный реактив является декларативным, высокоуровневым и кратким. К этому добавились два ограничения:

  1. Убедитесь, что любое затронутое производное используется только один раз для данной коллекции мутантов.
  2. Вывод гарантированно свежий, и его эффекты сразу видны любому наблюдателю.

Ограничение 1: так называемое «двойное исполнение». Если производное значение обеспечить, чтобы время зависело от другого производного значения, полученного для них в правильном порядке, чтобы исключить любую возможность прочитать устаревшие значения. Подробности того, как этот механизм работал в предыдущемСообщение блогаОписан раньше.

Ограничение 2: производно не старые, некоторые из более интересных. Он обеспечивает не только так называемые «глюки» (временные несоответствия), но и потому, что он представляет собой разные базовые средства, полученные планируемым.

const user = observable({
  firstName: “Michel”,
  lastName: “Weststrate”,
  // MobX computed attribute
  fullName: computed(function() {
    return this.firstName + " " + this.lastName
  })
})
user.lastName = “Vaillant”
sendLetterToUser(user)

Но, как мы сейчас видим, с помощью этой системы это намного эффективнее, чем ручная оптимизация кода.

Транзакции и действия

С небольшими усилиями мутации должны быть упакованы в транзакции, чтобы выполнение множественных изменений было атомарным. Выполнение форков откладывается до конца транзакции, но они все равно выполняются синхронно. Еще круче, если вычисленное значение используется до завершения транзакции, MobX гарантирует вам обновленное значение!

Немногие на самом деле используют транзакции явно, а в MobX 3 они даже устарели. Поскольку действие автоматически применяет транзакцию. Действия концептуально более элегантны; действие представляет собой функцию, которая обновляет состояние. React, с другой стороны, используется для реагирования на изменения состояния.

Концептуальная связь между действиями, состоянием, вычисляемыми значениями и реакциями

Расчетные значения и реакции

Еще одна вещь, на которой MobX уделяет особое внимание, — это разделение между значениями, которые можно вывести (вычисленные значения), и побочными эффектами, которые должны запускаться автоматически при изменении состояния (реакции). Разделение этих концепций является очень важной основой MobX.

Производная пример: синее наблюдаемое состояние, вычисленное зеленое, красное для реакций. Представляет собой светло-зеленый цвет, если на рассчитанное значение не наблюдается реакции (косвенной), она будет задержана. MobX гарантирует, что после мутации каждое производное выполняется только один раз в оптимальном порядке.

Причин несколько:

  1. Вычисленные значения принудительно исключают побочные эффекты. Поскольку у него не должно быть побочных эффектов, MobX может безопасно изменить его порядок, чтобы свести количество повторных запусков к минимуму. Можно просто подумать, что если вычисляемое значение не наблюдается, его вычисление выполняется лениво.

  2. Рассчитанные значения автоматически кэшируются. Это означает, что при прочтении вычисленного значения вычисления не будут перезапущены до тех пор, пока соответствующее наблюдаемое свойство неизменяется.

Сказав это, каждая программная система нуждается в побочных эффектах, таких как выполнение сетевых запросов или обновление DOM. Таким образом, нам всегда нужно привносить реактивность в императивный код, но такие реакции можно красиво инкапсулировать с помощью чистой абстракции, такой как компонент React Observer.

Таким образом, Mobx выясняется хорошее чувство пропорции, чтобы убедиться, что старые значения не наблюдаются, а полученные не запускаются часто, чем ожидалось. На самом деле, если нет активного слушания, рассчитать, что они не будут работать. На практике это может отличаться, для некоторого начального сопротивления MOBX, потому что люди привыкли к непредсказуемости MVVM Framework. Однако семантика четких действий, рассчитанных значений и реакций, не могут наблюдаться никаких устаревших значений, все полученные в том же стеке - я считаю, что эти факты будут иметь всю разницу.

Прокси и MobX

MobX широко используется в продакшне, поэтому обещаем запустить его в каждой среде ES5. Это позволяет использовать MobX в реальных браузерах, но также делает невозможной поддержку Proxy в настоящее время. По этой причине MobX имеет некоторые недостатки, такие как неполная поддержка свойств Expando для расширяемых объектов и использование искусственных массивов. Ни для кого не секрет, что со временем планировалось перейти на реализацию на основе прокси. В MobX 3 уже есть некоторые изменения для работы с прокси, и первые дополнительные функции на основе прокси уже не за горами. Но основная часть останется без прокси, пока ее не поддержит подавляющее большинство устройств и браузеров.

Дело о неглубоких структурах данных

Концепции модификаторов/мелких наблюдаемых останутся в MobX в той или иной форме, вне зависимости от того, переходить на реализацию Proxy в будущем или нет.

Причиной сохранения механизма модификаторов является не производительность, а интероперабельность.

Когда все данные во время состояния приложения находятся в контроле, автоматическая наблюдаемость очень удобна, MobX также основывается на этом запуске разработки. Но иногда вы обнаружите, что мир не так хорош, как вы ожидаете. Каждое приложение имеет ряд банков, каждый по своим правилам, нес свои идеи. Введены модификаторы MobX и неглубокие коллекции, чтобы четко различать, какими данными можно управлять MobX.

Например, иногда вам нужно хранить ссылку на внешние концепции. Тем не менее, внешний объект управления базами данных (E.G. JSX или DOM-элемент) может быть автоматически преобразован в объект наблюдения, часто не соответствует ожиданиям, он очень прост в включении внутри внешней библиотеки. Вы можете легко найти некоторые в Thumbx Tracker Tracker в непреднамеренном объекте в объект можно наблюдать неожиданное поведение вызвало проблемы. Модификаторы не «делают вещи правильными, как только это» означает, а скорее «только для соблюдения ссылки на объект, сам объект считается вне контроля черный ящик».

第二个问题是自动可观察集合总是创建“克隆”,这并不总是可以接受的。 Proxy 总是产生一个新对象,并只以“一个方向”工作。如果由最初的库改变了一个 proxy 对象的原始对象值,则 proxy 无法知道这个改变。 следующим образом:

const target = { x: 3 }
const proxy = createObservableProxy(target)
observe(() => {
 console.log(proxy.x)
})
target.x = 4
// proxy.x 现在是 4, 但是没有log被打印,就是说 proxy 的 setter 没有被调用!

Тем не менее, способ, которым NX генерирует наблюдаемые прокси-серверы на лету во время чтения, очень интересен. Я не совсем уверен, как он справляется с ссылочной прозрачностью, но, похоже, пока он делает это довольно умно. Избегать модификаторов, читая и записывая $row, очень интересно. Я не уверен, что это обеспечит чистое чтение и запись, но это, безусловно, сэкономит затраты на введение таких концепций, как мелкое.

Что делает неотслеживаемый?

Необходимое небольшое замечание о семантике untracked заключается в том, что, в отличие от логического вывода, оно не имеет ничего общего с обновлением NX $row . В MobX данные не могут быть обновлены без уведомления наблюдателей, а также вводит возможность устаревших данных в приложении, что противоречит философии MobX. Людям иногда нужен этот механизм, но я не встречал практического варианта использования, который был бы концептуально неразрешим.

Удовлетворенные делают наоборот: не волнует неосторожным пишетом, и только сделать только чтение без упущенного. Другими словами, этот подход означает, что нам все равно, что нас не волнует будущие обновления данных, которые мы используем. Как транзакции, это API редко используется на практике, но механизм обработки в действиях имеет большой смысл концептуально: действия, которые работают в ответ на пользовательские события, а не из изменения, поэтому они не должны отслеживать данные, которые они используют - эти вещи это то, что делает реакция.

Суммировать

MobX разработан как общая реактивная библиотека приложений, а не просто набор инструментов для повторного рендеринга пользовательского интерфейса.

Вместо этого он продвигает идею о том, что хорошо работает (как производительность, так и эффект), когда данные должны быть как можно более выведены из других данных. MobX также легко использовать в бэкэнд-процессе. Синхронный запуск выводов и отделение вычисляемых значений от реакций — это основа MobX, которая приводит к более чистой деструктуризации состояния приложения.

Наконец, nx-observe доказывает, что прокси — очень жизнеспособная основа для прозрачных библиотек реактивного программирования, как концептуально, так и с точки зрения производительности.

----------------------------------------

Нажмите и удерживайте QR-код или найдите немного жизни, чтобы подписаться на нас