All streams
Search
Write a publication
Pull to refresh
12
0
Сергей @redyuf

Программист веб и не только

Send message
Странно, Core i7-4550U 1.50GHz и 61-м хроме на убунте

10 вкладок с треугольником на mol летают (видимо я уже обновленную версию открыл), грузят где-то 10%, а на реакте под 100% все ядра грузят и вычисления стоят на одной цифре, правда анимация наиплавнейшая.

У вас, я так понимаю срабатывает трюк: если вкладка не видна, вычисления засыпают.
Тогда потеряется львиная доля преимуществ и получится шило на мыло.
Что-то потеряется, к сожалению. Мое предположение в том, что из-за конкуренции в вебе и js, вам без огромных вливаний ресурсов, как у гугла в ангулар, не продать огромный кусок чего-то сильно отличающегося.
У всех космические корабли похожи на энтерпрайс, у вас на инопланетную губку из водорослей, где все замкнуто на вас:
1. Свои соглашения по импортам и связянного с ними стилем кодирования
2. Необычная реализация инверсии контроля через контексты
3. Своя экосистема: пакетный менеджер и сборщик зависимостей (mam)
4. Своя библиотека для DOM, http и пр. утиль
5. Своя библиотека работы со стейтом (mol_atom), с удачной, но непривычной идеей в основе
6. Иерархическое наследование на tree, вместо плохо кастомизируемой, но простой и понятной всем композиции на шаблонах, таких как JSX

Это все может быть 100 раз оправданно, цельно и логично и опережать время лет на 5, но оно просто ни на что не похоже. Аналогии не работают, т.к. это новый подход к разработке в целом. Может попробовать продать маленький кусок, встроив в привычную экосистему, как автор mobx?

А где на него посмотреть?
Мне б тоже хотелось знать, может просто их спросить? Я помню как автор mobx много где упоминал свое решение пару лет назад, тогда еще mobservable, например как здесь и у него было пару десятков звезд, а сейчас 11К.
1. Слишком много новых концепций. Например, может лучше начать с mol_jsx, вместо tree, т.к. многие не хотят это постигать целиком
2. Нужны примеры в сравнении с аналогичными на react
3. Статьи на англоязычные ресурсы
4. Посмотреть на опыт авторов mobx, catberry, авторы которых с нуля и быстрее вас получили намного больше звезд

А в реальности, мне кажется, что только много денег, вложенные в маркетинг, могут помочь, у меня то всего 20 звезд на гитхабе, около 100 у вас это еще неплохо =)
Неубедительная аргументация, если честно. Артефакт может зависеть от загрузки процессора, версии файбера и расстановки приоритетов компонентам.

Во-первых, надо уточнить случаи, когда
рендеринг каждого кадра важнее скачков анимации и доказать, что это так.

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

компоненты должны быть декомпозированы очень сильно. Чем меньше кирпичик — тем выше производительность. К чему и тяготеет мол.
Тут хотелось бы понять, какой пример мы обсуждаем: mol_jsx, mol или некий абстрактный на mobx и react без vdom на реальном dom.
Если я правильно вас понял, вы считаете, что все DOM-элементы в компоненте будут пересозданы, если какое-либо его observable-свойство поменялось.
Так реализация прослойки между mobx и DOM должна точечно мутировать DOM-ноду, если надо поменять одно из ее свойств или дочернюю ноду, как это и делает mol_jsx.

Наверное есть случаи, где такой подход будет работать хуже vDOM, но тут надо конкретный пример рассматривать и оценивать насколько это критично.
Для mol, лучше бы vintage объяснил, что будет, если делать все здоровенными компонентами.

вы должны быть уверены, что в вашем проекте нет узких мест, которые зафризят UI. Сюда включается и начальный рендер (от чего мол убежал с мотивацией «так код будет более идиоматичный») и тяжёлые обновления (а от этого мол не смог убежать — фризы на демках появляются регулярно).
Тут не понял. Как vDOM может уберечь от фризов? Что такого было бы в приложении с mobx и нативном DOM, что фризило бы рендеринг?

Подозреваю, что вместо реакта должно быть «ридакс»?
Именно реакта. Посыл был в том, что mobx делает многие вещи ненужными в реакте. Если бы проектировать начали с слоя данных, то дальше многие проблемы решать было бы проще. В Vue, кстати, в основе нечто похожее на mobx.

Почему не с redux, потому что это opinionated-подход, навязывающий определенный архитектурный стиль.
Mobx же претендует на unopinionated: обычные классы, минимум инфраструктурного кода. Нравится функциональный стиль — пожалуйста, mobx хорошая платформа для построения mst-подобных решений.
Можно было бы оставить только pure-компоненты, зоопарк способов менять состояние свелся бы к единообразному подходу на основе mobx и его надстройках. Все были бы счастливы.

shouldComponentUpdate и не нужен для того случая, который вы описали
Я показал, что в mobx, observer его реализует одинаково для всех оборачиваемых pure-компонент.

Не знаю, в курсе ли вы, но в recompose есть и более вкусные вещи: onlyUpdateForKeys() и onlyUpdateForPropTypes(). ShouldComponentUpdate нужен в очень редких случаях.
Изначальная идея — автоматически ускорить рендеринг и вдруг, для некоторых случаев, предлагается это делать вручную. Вопрос, где слабое звено в фреймворке, из-за которого возникла такая потребность? В vue как-то без shouldComponentUpdate обходятся.

Основной посыл был в том, что с mobx меньше инфраструктурного кода. Конечно со всякими redux-saga тоже меньше, но тут смысл в unopinionated, появляется выбор: можно напрямую в mobx состояние актуализировать, а можно и mst и saga-подобные решения накручивать.

P.S. пример с моловским треугольником стал тормозить уже после 5-й открытой вкладки, в то время как демонстрация файбера
Я к тому, что mol по сравнению с реактом без файбера выдавал лучшую производительность, сравнимую с реактом с файбером на одной вкладке, да.
Было б прикольно, если б vintage запилил свой файбер, но он наверное опять скажет «не нужно».
Всегда ли плавность важнее гарантированного отклика? Да и почему, собственно, понадобилось добавлять какой-то Fiber для видимости ускорения? Для меня убедительно выглядит пример треугольника на mol, который обеспечивает плавность без технологий, вроде Fiber. И для этого надо раз в 5 меньше кода и это все написал один человек, а не команда из гиганта FB.

Используя mobx, мы большую часть оптимизаций перекладываем с vDOM на mobx. Если эту идею довести до логического конца, то зачем тогда vDOM?.. А если не нужен vDOM, то некоторая часть реакта становится бесполезным оверхедом. Автор mol как раз это показал, написав небольшой наколеночный jsx-процессор на нативном DOM, сопоставимый с vDOM по производительности.

Рекомендации будут в случае любого фреймворка. Тут вопрос, не является ли часть из них следствием неудачных решений, принятых где-то раньше? Что было бы с рекомендациями, если бы перед реактом сделали mobx?

Вместо redux мы бы сразу получили mobx-state-tree с его децентрализованным стейтом и другими фичами.

shouldComponentUpdate стал бы не нужен, т.к. mobx решает эту проблему автоматически, не привнося сложности в прикладной код. Observer просто делает shallowEqual при любом обновлении данных.

componentWillMount стал бы не нужен, т.к. актуализацию данных можно делать в роутере или в самих данных (через fromPromise и lazyObservable из mobx-utils). О чем и говорит Michel Weststrate в статье How to decouple state and UI
У файбера есть и недостатки: плавность, ценой пропуска кадров. Это проявляется, если проц слабый или загружен. Откройте 10 демок на файбере и в одной повозите мышкой над цифрами. Проблему производительности он скорее маскирует, чем решает. Может быть когда-нибудь в многопоточной среде и будет решать, но не в однопоточной.

Про скорость repaint в DOM, мне кажется, Дмитрий имел в виду, что если на странице много элементов, в том числе и за пределами видимой области, то это будет тормозить. И vDOM тут никак не поможет.

vDOM не бесплатный, поэтому есть shouldComponentUpdate, отчасти setState, а также много попыток написать быстрее, чем в react (тот же inferno или ivi).

vDOM — это оптимизация внизу, перед выводом в браузер. А mobx-подобные решения — это оптимизация наверху, сразу после изменения данных. Что может быть гораздо быстрее любого vDOM, т.к. глубина вычислений будет меньше в среднем случае.

Многие фреймворки добиваются высокой производительности, используя точечные обновления, вместо vDOM (тот же angular4, отчасти vue). Интересно наблюдать, как развивается этот альтернативный подход, в том числе и в mol.
На мой взгляд, изолированные бенчмарки алгоритмов тоже нужны. Тут дело в нестандартных условиях, которые нельзя предугадать. Например, что такое видимая область, это сколько?

А если стена из мониторов, с очень большим суммарным разрешением?

А если это приложение на каком-нибудь electron или phantomjs, задача которого срендерить много-много страниц pdf? Хотя тут наверное SSR поможет, а он у вас без такой оптимизации.

Как будет масштабироваться mol в сравнении с конкурентами на нестандартные решения? Хоть это сейчас и редкие случаи, но интересный был бы задел на будущее.
Вы не думали сделать эту фичу отключаемой? Кому очень нужен Ctrl-F, для бенчмарков и для споров.

Отстали бы те, кто использует аргумент ленивости против mol.

Т.к. я использовал атомы (основу mol) вместе с реактом и делал бенчмарки, то думаю, что mol все-равно бы в среднем чуть обгонял популярные фреймворки за счет легковесности.

Даже если скорость будет такая же, она достигается гораздо более простыми алгоритмами, в 5 раз меньшим объемом кода, кастомизируемостью, которых нет у других, а это уже аргумент.
В голову приходит что-то из разряда ненормального программирования: работа с DOM как с пикселями, графики на DOM-элементах, ASCII-подобные мультики.

Вопрос в другом, почему mol на видимой области медленнее vdom, чему там тормозить, если обновления точечные и все-равно все упирается в DOM?
Еще раз: JavaScript на клиенте не лагает. Лагает медленный DOM (точнее манипуляции с DOM).

Из этой фразы можно подумать, что проблемы только в DOM, лагает он и все тут. А как только его ускорят, все фреймворки залетают.

DOM медленный, но есть тот же mol, который работает с реальным DOM напрямую и судя по todomvc бенчмаркам (раз, два), гораздо быстрее многих фреймворков вроде реакта и ангулара. Дело в том, как изменения в стейте отражаются на DOM, в цене минимизации обновлений, а это уже архитектурные проблемы на стороне фреймворка.
Ускорив DOM, можно только замаскировать эти проблемы, задвинуть их на второй план.
Спасибо за идею, накидал такой пример. Позже напишу статью с его разбором.
Удалить и заменить деталь внутри можно, а вот что бы добавить, надо делать композицию заново (правда, в отличие от чистого реакта, в rdi это можно проделать не для основного компонента, а для его внутренней детали). У вас, в tree, такая перекомпозиция происходит дешево в sub.

Пока не представляю как в jsx это также дешево сделать. Можно выделять детали на первом уровне в компоненты и делая компонент, который выстроит последовательность из этих деталей.
А что, по-вашему, должно быть в базовой версии, а какие возможности добавлять при ее расширении?
Это первая моя статья, буду пытаться улучшать подачу в следующих. Хотя бы пример с HelloWorld понятен? Могу для сравнения еще насоздавать, только задачу сформулируйте.

Суть такая примерно:
  • Развить идею контекста в реакте
  • Привнести SOLID на фронтенд наименьшей ценой
  • Дать возможность писать код, максимально свободный от каркаса, убрав vendor lock-in
  • Использовать типы и DI для связывания частей, вместо решений вроде connect, redux-thunk, reselect и т.д.

Сложность уменьшается за счет простых базовых концепций, которые позволяют писать меньше кода, оставляя его понятным (хочется верить).
  • mem — декоратор, если имеется в виду реализация, то это отдельная библиотека, о ней я планировал в другой статье рассказать.
  • Параметры: github.com/tc39/proposal-class-fields
  • Типы не стандарт ES, но поверх наслаивается: flowtype, typescript.

В TypeScript строковые литералы не считаются нетипобезопасными, так как есть строковые литеральные типы.
В ts да, такая штука будет типобезопасной:
import { InjectionToken } from '@angular/core';
interface AppConfig {
  title: string;
}
export let APP_CONFIG = new InjectionToken<AppConfig>('app.config');
//...
constructor(@Inject(APP_CONFIG) config: AppConfig) {
  this.title = config.title;
}

Однако такой подход все-равно требует расстановки декораторов, это не нативно из-за InjectionToken. Второй момент — заранее надо продумывать точки расширения, расставляя эти декораторы.

Redux предназначен не для хранения состояния компонентов.
Redux лучше впишется туда, где используются транзакции, timetravel, распределенная работа с данными. Если эти навороты не нужны, то есть более простые способы менять состояние, поэтому многие перешли на mobx.
Задачу связывания redux решает не очень хорошо: redux-thunk, reselect, connect — низкоуровневые инструменты. Если основа DI, можно все связывание построить на типах, не привнося фреймворко-специфичных конструкций.
Сравните примеры Hello world, кода сильно меньше при сравнимом уровне абстракции:
На redux
import { connect } from 'react-redux'
import React, { PropTypes } from 'react'

const HELLO_WORLD = 'HELLO_WORLD'

const helloWorld = (state = { message: 'Hello' }, action) => {
  switch (action.type) {
    case HELLO_WORLD:
      return Object.assign({}, state, { message: 'Hello, World!' })
    default:
      return state
  }
}

const Hello = ({ onClick, message }) => {
  return (
    <div>
      <h1>{ message }</h1>
      <button onClick={onClick}>Click</button>
    </div>
  )
}

const mapStateToProps = (state, ownProps) => {
  return {
    message: state.helloWorld.message
  }
}

const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    onClick: () => {
      dispatch({ type: HELLO_WORLD })
    }
  }
}

const HelloWorld = connect(
  mapStateToProps,
  mapDispatchToProps
)(Hello)
На reactive-di
import {mem} from 'lom_atom'
class HelloWorldStore {
  @mem message = 'Hello'
   onClick() {
      this.message = 'Hello, World!'
   }
}

function HelloWord(_: {}, store: HelloWorldStore) {
  return (
    <div>
      <h1>{ store.message }</h1>
      <button onClick={() => store.onClick()}>Click</button>
    </div>
  )
}

Через алиасинг HelloWorldStore также можно разделить компонент и реакцию на событие.

Без lifecycle очень плохо.
Тут бы глянуть конкретные примеры. Есть мнение, что если правильно построить работу с состоянием, большинство lifecycle не нужными становятся. Я об этом хотел написать в следующей статье.
Например, hello world с загрузкой, обработкой ошибок и крутилкой:
На reactive-di
function fetchName() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // reject(new Error('Fetch error'))
      resolve({name: 'John'})
    }, 500)
  })
}

interface HelloModel {
  name: string;
}

class HelloService {
    @mem set hello(next: HelloModel | Error) {}
    @mem get hello(): HelloModel {
      fetchName()
        .then((model) => { this.hello = model })
        .catch((error) => { this.hello = error })

      throw new mem.Wait()
    }
}

function HelloView(props: {greet: string}, service: HelloService) {
    return <div>
        {props.greet}, {service.hello.name}
        <br/><input value={service.hello.name} onChange={(e) => { service.hello = {...service.hello, name: e.target.value} }} />
    </div>
}

ReactDOM.render(<HelloView greet="Hello"/>, document.getElementById('mount'))
fiddle
На angular4
import {Component} from '@angular/core';

function fetchName() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // reject(new Error('Fetch error'))
      resolve({name: 'John'})
    }, 500)
  })
}

interface HelloModel {
  name: string;
}

export class Hello implements HelloModel {
  name = 'Vasian'
}


@Component({
  selector: 'my-app',
  template: `
    <div>
    <div *ngIf="error; else elseBlock">
      {{error.message}}
    </div>
    <ng-template #elseBlock>
  {{greet}}, {{hello.name}}
  <br/><input [(ngModel)]="hello.name">
    </ng-template>
    </div>
`
})
export class AppComponent  {
  greet = 'Hello';
  error: any = '';
  hello: Hello = new Hello()

  ngOnInit() {
    fetchName()
      .then(hello => this.hello = hello)
      .catch(error => this.error = error)
  }
}
plnkr

Как минимум, загрузку и ошибки в Angular придется обрабатывать вручную. Красивый биндинг данных работает внутри компонента, если нужна декомпозиция Hello (например расшарить между двумя компонентами, ничего не знающими друг о друге), то уже надо тащить стримы, подписываться/отписываться.
Что бы использовать сервис, надо объявить его в provide и помечать Injectable. А typescript работает внутри Angular template, как в JSX?
Объем кода тоже можно отметить, Angular4 core+common+forms = 13459 SLOC, rdi+lom_atom+preact, на котором мои примеры, около 2048 SLOC.
Тут конечно простые примеры рассмотрены, если подкинете сложные, я их запилю на rdi.
DI мне интересно развивать, как фундамент для связывания частей приложения, без привязки к каким либо фреймворкам. Еще была важна ненавязчивость, в коде нету import some from 'reactive-di' (кроме cloneComponent), только чистые функции + метаданные.

Redux немного другие задачи решает, навязывает определенный стиль программирования (экшены, редьюсеры и т.д.) не избавляет от HOC и этого connect в коде. Если нужны транзакции, версионирование и т.д., то решения вроде redux можно накрутить и поверх DI. Например, mobx-state-tree — это как раз пример того, как выглядел бы redux поверх mobx.
А пример можно? Глянул бы.
Вы какой-то конкретный пример имели в виду? Вроде вполне стандартный js с flow-типами и JSX.

Information

Rating
Does not participate
Location
Россия
Registered
Activity