Comments (14)
Привет, в 1.6.58
добавил cellx.transact
.
Мне кажется, что mobx.transaction
немного неправильно работает:
let num = mobx.observable(1);
let num2 = mobx.observable(2);
try {
mobx.transaction(() => {
num.set(2);
num.set(3);
num2.set(5);
throw 1;
num2.set(10);
});
} catch (err) {}
console.log('num: ' + num.get());
// => "num: 2"
console.log('num2: ' + num2.get());
// => "num2: 5"
Из википедии:
Транза́кция — минимальная логически осмысленная операция, которая имеет смысл и может быть совершена только полностью.
То есть mobx должен откатить изменения из-за ошибки и последние два console.log-а должны вывести "num: 1" и "num2: 2".
У меня вроде получились правильные транзакции:
let num = cellx(1);
let num2 = cellx(2);
cellx.transact(() => {
num(2);
num(3);
num2(5);
throw 1;
num2(10);
});
console.log('num: ' + num());
// => num: 1
console.log('num2: ' + num2());
// => num2: 2
отладка
порядок вычисления в синхронном режиме может заметно измениться и такая отладка скорее оставит ещё больше вопросов.
обработка ошибок
это актуально для mobx который падает при ошибке в формуле, cellx в этом случае создаёт на ячейке событие error
, оно же распространяется по всем вычисляемым ячейкам. Единственный способ добиться падения -- запись в невычисляемую ячейку, но тут и до вычисления просто не доходит. В общем, совсем другой подход к обработке ошибок.
Если всё равно очень нужно, то можно включать костылём вроде такого (не проверял):
let originalSet = cellx.Cell.prototype.set;
cellx.Cell.prototype.set = function() {
originalSet.apply(this, arguments);
cellx.Cell.forceRelease();
};
но добавлять это в библиотеку как-то не хочется, так как костылище)).
from cellx.
Спасибо.
порядок вычисления в синхронном режиме может заметно измениться и такая отладка скорее оставит ещё больше вопросов.
Не очень понимаю о чем речь, пример можно?
from cellx.
http://jsbin.com/cudevigobe/edit?js,console
асинхронно: "c", "d"
синхронно: "d", "c", "d".
from cellx.
Несколько set нужно делать только внутри транзакции. Транзакции через таймеры, которые сейчас, хоть и просто, но это магия, некое соглашение, поведение которого нельзя изменить. В коде лучше явно сказать, что эти апдейты внутри транзакции, чем держать в голове, что они выполнятся в следующем тике.
Как быть с известной реактовой багой, когда курсор перескакивает в начало инпута, если стейт обновился асинхронно. Скорее forceRelease (как и любой другой force*) выглядит костылем, чем синхронное обновление+транзакции.
По поводу обработки ошибок: http://jsbin.com/kesiperese/1/edit?js,console
Если откомментарить // cellx.Cell.forceRelease();, то виден весь путь до ошибки, а без него, только до cellx.
В баобабе, например, тоже изначально только через таймеры были транзакции, потом автор добавил параметр asynchronous, по-умолчанию он true, но скорее всего это из-за совместимости с легаси.
from cellx.
В 1.6.60
синхронный режим можно включить так:
cellx.configure({ asynchronous: false });
from cellx.
Спасибо, работает.
Баг только обнаружил:
let a = cellx(1);
cellx.configure({ asynchronous: false });
function fn(err, evt) {
console.log(evt.value)
}
console.log('start')
var o = {a: a}
o.a('subscribe', fn)
a(2) // ничего не выведет
cellx считает o.a() и a() как разные ячейки
http://jsbin.com/hobikigeju/edit?js,console
from cellx.
Это фича)) Значение ячейки привязано к контексту в котором она запускается, это необходимо для возможности объявления ячеек в прототипе:
function User() {}
User.prototype.name = cellx();
var user1 = new User();
var user2 = new User();
user1.name('Матроскин');
user2.name('Шарик');
console.log(user1.name());
// => "Матроскин"
Без этой фичи user1.name()
вдруг станет Шариком.
Если это не нужно, можно использовать внутренний класс cellx.Cell
, сам cellx
-- это просто обёртка над ним, реализующая всякие такие странности с контекстом.
function User() {}
User.prototype.name = new cellx.Cell();
var user1 = new User();
var user2 = new User();
user1.name.set('Матроскин');
user2.name.set('Шарик');
console.log(user1.name.get());
// => "Шарик"
from cellx.
Ок, не совсем очевидно как-то. Действительно так нужны эти упрощения в виде одной god-функции в ущерб явности? Может хотя бы какой-нить cellx.prop сделать ?
В mobx более логично выглядит extendsObservable(this, {bla-bla}), да, в конструкторе, но код понятнее получается.
На мой взгляд, проблема на стыке атомов и обычного кода, в mobx magic get/set, в cellx свойства похожиме на get/set методы. Из-за этого куча извратов городить приходится.
Например, в погоне за похожестью на привычный многим код, без оберток над данными, у тебя используется антипаттерн строковая типизация. Например, a('subscribe', fn) - по сути вызов метода a.subscribe(fn)
Если взять flow или typescript и по-честному, без any, переписать тип ICellx, то ни typescript, ни flow его не переварят, т.к. там нет паттерн-матчинга по сигнатуре функции.
Может конечно не так что-то делаю, вот пример на typescript:
type CellxEvent<V> = {
type: 'change';
oldValue?: V;
value: V;
}
type ListenerName = 'addChangeListener' | 'removeChangeListener'
type CellxListener<V> = (eventName: ListenerName, fn: (event: CellxEvent<V>) => void) => void
type CellxSet<V> = (v: V) => void
type CellxGet<V> = () => V
type CellxAtom<V> = CellxListener<V> | CellxSet<V> | CellxGet<V>
type Cellx<V> = () => CellxAtom<V>
var f: any = 0
var fn: Cellx<number> = f
var a: CellxAtom<number> = fn()
var val: number = a() // Can not invoke an expression ...
По мне, идея atom-подобных оберток внутри обычного кода - костыль. Нужно наоборот, при помощи инверсии контроля
выполнять обычный код внутри атомов, т.е. di-контейнер управляет не только созданием объектов, но и их реактивностью, вынося за сцену все эти get/set, computable, observable, action.
from cellx.
так нужны эти упрощения в виде одной god-функции в ущерб явности
современные js-движки развращают своей скоростью, раньше создавать методы в конструкторе было страшным грехом, а сейчас пожалуйста, сколько хочешь. Объявление ячейки в прототипе позволяет не создавать функцию на каждое свойство каждого экземпляра, плюс экземпляры cellx.Cell
создаются при этом лениво, при первом обращении к свойству. Это лучшее сочетание скорости и удобства.
Если же скорость и потребление памяти не особо важны, то есть cellx.define
:
function User(name) {
cellx.define(this, { name: name });
}
var user1 = new User();
var user2 = new User();
user1.name = 'Матроскин';
user2.name = 'Шарик';
console.log(user1.name);
// => "Матроскин"
Ещё более современный вариант: cellx-decorators.
Про странный синтаксис вызова методов рассказывал здесь: #8 . К написанному там можно добавить, что с новым, уже описанным в стандарте __proto__
, подставить свой прототип функции всё же можно (IE11+):
function f() {}
f.__proto__ = { __proto__: Function.prototype, myProp: 1 };
console.log(f.call);
// => function call() { [native code] }
console.log(f.myProp);
// => 1
То есть при желании можно добиться и a.subscribe(fn)
без переписывания методов в цикле как в том же KnockoutJS. Тут нужно будет поисследовать насколько это быстрее/медленнее. Сейчас я просто давно уже перешёл на декораторы и cellx.define
, так что уже не заморачиваюсь на эту тему)).
С тайпскриптом давно не работаю, раньше использовал эту типизацию: https://github.com/Riim/cellx/blob/master/src/cellx.d.ts . Стараюсь обновлять её стабильным функционалом, вроде должна быть рабочей.
from cellx.
по поводу #8, ну да, не берусь тут судить, производительность наверняка выше и памяти поменьше ест, если контекст не передавать ссылкой, а this использовать.
Просто выглядит не очень очевидно с контекстом, но это из-за решения проблемы "как сделать код с атомами похожий на код без атомов с минимальным оверхедом".
Про интерфейс, формально он есть и рабочий, но на мой взгляд больше для галочки. Я про интерфейс именно фасада cellx, сам класс Cell то норм.
interface Cell<T> {
get(): T;
...
}
interface ICellx<T> {
(value?: T): T;
(
method: string,
arg1: any,
arg2?: any,
arg3?: any,
arg4?: any,
arg5?: any
): ICellx<T> | Error | Promise<any> | Cell<T>;
}
var a: ICellx<number>
a('test', 'some').get() // Property get does not exists...
from cellx.
Поправил типизацию:
Lines 231 to 250 in 01457e6
from cellx.
о, теперь понятно, спасибо.
Немного отвлеченный вопрос, а не мог бы ты описать трюки, которые позволяют увеличить производительность и снизить потребления памяти. Примерно как Optimization-killers у petkaantonov.
Есть общеизвестные - не использовать генерацию функций, миксины вместо new Class, но может в твоем опыте что-то еще есть?
from cellx.
Вряд ли мой опыт заметно отличается от того, что можно найти в Интернете, но я подумаю)).
from cellx.
Т.к. cellx.transact добавлен и моя хотелка выполнена, тикет закрою.
from cellx.
Related Issues (20)
- Guidance requested
- Untranslated part of README HOT 1
- Одно вычисление а не два HOT 2
- Please include Sodium FRP in your PERF
- Как сделать подписку с учётом будущих изменений? HOT 6
- Сломаны removeChangeListener и unsubscribe HOT 4
- dispose throws unexpectedly HOT 1
- why a varargs/overloaded API? HOT 2
- consider switching to Rollup HOT 5
- Good way to implement auto-run? HOT 3
- create-react-app TypeError: undefined has no properties _on EventEmitter.js:102 HOT 14
- Error rethrowed only once HOT 12
- Зачем `let reactions = this._reactions;` HOT 1
- Ожидание корректного значения HOT 1
- Почему dep._addReaction после pull делает ячейку DIRTY? HOT 1
- _deactivate() не чистит this._dependencies HOT 5
- После fail executon всея ячейки дерева state ACTUAL HOT 4
- Async cell HOT 3
- value instanceof EventEmitter. Подписка в конструкторе HOT 1
- "effects" in cellx HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from cellx.