Download - Observable как атом приложения
Observable как атом приложения
Я
Артем Бей - разработчик интерфейсов
@defly_self
http://tweereal.com/
http://youscan.ru/ (мониторинг соц. медиа)
“we believe that the essential material to be
addressed by a subject at this level is not the
syntax of particular programming-language
constructs, nor clever algorithms for
computing particular functions efficiently, nor
even the mathematical analysis of
algorithms and the foundations of
computing, but rather the techniques used to
control the intellectual complexity of
large software systems.”
Structure and Interpretation of Computer Programs
<button onclick=‘handler()’>
$(‘.click-button’).click(handler);
фреймворки, AMD и даже новые языки
программирования (Dart, ClojureScript,
CoffeeScript, TypeScript и тд).
В чем сложность?
В событиях!
• Сложно компоновать несколько событий
• Сложно соблюдать очередность
• Одни события могут создавать другие и
за этим всем сложно следить
Способы борьбы
• Дисциплина
• Control-flow библиотеки
• Promises
Control-flow
async.parallel([function(callback){
setTimeout(function(){callback(null, 'one');
}, 200);},function(callback){
setTimeout(function(){callback(null, 'two');
}, 100);}
],// optional callback
function(err, results){// the results array will equal ['one','two'] even though// the second function had a shorter timeout.
});
Promises
Q.fcall(step1)
.then(step2)
.then(step3)
.then(step4)
.then(function (value4) {
// Do something with value4
}, function (error) {
// Handle any error from step1 through step4
})
.done();
Functional Reactive Programming
FRP
Обработка данных
которые меняются со
временем
События оборачиваются в потоки,
которые возможно
• Фильтровать
• Объединять (merge)
• Комбинировать (zip)
• Тротлить (throttle)
• Преобразовывать
• Буферизировать
• и так далее...
Сервис подсказок (RxJS)
/* Only get the value from each key up */var keyups =Rx.Observable.fromEvent(input, 'keyup')
.select(function (e) {return e.target.value;
}).where(function (text) {
return text.length > 2;});/* Now throttle/debounce the input for 500ms */
var throttled = keyups.throttle(500 /* ms */);/* Now get only distinct values,
so we eliminate the arrows */
var distinct = keyups.distinctUntilChanged();
Сервис подсказок - 2 (RxJS)
var suggestions = distinct
.select(function (text) {
return searchWikipedia(text);
})
.switchLatest()
.where(function (data) {
return data.length == 2 && data[1].length > 0;
});
Ещё проще!
(уменьшаем наши требования)
Данные + события
Данные которые меняются
Данные + событие
Observable
Observable на js-псевдокоде
function Observable () {var value; // valuevar subscribers; // [sub1, sub2, ...]
function notifySubscribers() {subscibers.forEach(notify);
}
this.addSubscriber = function(subscriber) {//...subscribers.push(subscriber);
}
this.removeSubscriber = function(subscriber) {// scan and remove subscriber
}
this.setValue = function(newValue) {//...if (!equal(value, newValue)) {notifySubscribers();
}}
this.getValue = function() {//..
}}
Knockout style API
observableExample = observable(); // create observable
observableExample(value); //set value
observableExample(); //get value
observableExample.subscribe(newValueHandler);
Подписчики или
зависимые observables
Подписчик - тот же observable, у
которого значение всегда
соответствует значению заданной
функции, аргументы которой другие
observable.
Computed
var x = observable(0);
var y = observable(0);
var r = computed(function() {
return Math.sqrt(x()*x() + y()*y());
});
Computed. Обратная операцияvar r = computed({
read: readHandler,// previous
write: function(r) {
if (r >= 0) {
x(r*Math.cos(Math.PI/4));
y(r*Math.sin(Math.PI/4));
} else {
throw new Error(‘Не может быть отрицательным’);
}
}
});
Computed. Пример из жизни
var isFormValid = computed(function() { return (login().length > 2) && (password().length > 5);
});
var canSend = computed(function() { return !messageSent() && !loading() && isFormValid();
});
Observable коллекции – скажут
подписчикам, что изменился
набор её элементов (а не сами
элементы)
id1 id2 id2
user1 user2 user2
fullProfile1 fullProfile2 fullProfile3
id1 id2
user1 user2
fullProfile1 fullProfile3
В масштабах приложения
WebSockets Repository Workers
Observables
UI (data binding)
Возможные проблемы
• Иногда необходим computed.dispose()
• Throttle
• Производительность (много работы за
бортом)
Profit
• Декларативность
• Тестируемость
• Круто работает в связке с data binding
• Snapshots
Что посмотреть и почитать?
RxJS, Bacon.js;
Knockout (Knockup, Durandal);
obs (https://github.com/pluma/obs) + Rivets;
Прочитать SICP
http://awelonblue.wordpress.com/2012/07/01/why-not-
events/
http://elm-lang.org/
https://speakerdeck.com/search?q=frp