forked from pimenovoleg/fost.github.io
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from 7235200/rx-read
Rx read
- Loading branch information
Showing
11 changed files
with
217 additions
and
91 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
_site | ||
.sass-cache | ||
.jekyll-metadata | ||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -58,4 +58,4 @@ RUBY VERSION | |
ruby 2.4.0p0 | ||
|
||
BUNDLED WITH | ||
1.13.7 | ||
1.14.3 |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
--- | ||
layout: post | ||
title: "RxJS - Часть 2, Observable" | ||
date: 2017-01-30 | ||
description: RxJS Observable | ||
categories: | ||
- rxjs | ||
- tutorial | ||
- 10 min read | ||
permalink: rxjs/observable | ||
--- | ||
|
||
test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
--- | ||
layout: post | ||
title: "RxJS - Часть 1, Введение в реактивное программирование" | ||
date: 2017-01-30 | ||
description: Введение в реактивное программирование | ||
categories: | ||
- rxjs | ||
- tutorial | ||
- 10 min read | ||
permalink: rxjs/reactive | ||
--- | ||
|
||
## A = B + C | ||
В современном мире сложных высоконагруженных веб приложений, где компоненты одной страницы исчисляются десятками, | ||
а изменение состояния одного из них порождает цепочку различных событий по всему приложению, существует | ||
закономерная проблема отслеживания таких изменений и управления ими. К решению этой проблемы, а именно к осмыслению | ||
приложения, построению взаимодействия внутри него и, наконец, написанию кода, можно подойти с разных сторон, однако | ||
интуитивно логичнее и чище в этом случае выглядит парадигма реактивного программирования. | ||
|
||
Существует множество определений понятия реактивности, которые разнятся от запутанных до очень запутанных | ||
и, поначалу, не вносят особой ясности. Хотя, если говорить абстракциями, все не так уж и сложно: `A = B + C` | ||
|
||
> В случае императивного программирования после момента присваивания, переменная A будет | ||
существовать независимо от B и С на всем протяжении жизненного цикла программы, в то время как в реактивном | ||
программировании при изменении B или C, значение A будет автоматически пересчитано | ||
|
||
Получается, практически все в нашем вышеописанном приложении подчиняется реактивному поведению, а обработкой такого | ||
поведения как раз и занимается реактивное программирование. **Реактивное программирование - обработка параллельных потоков данных** | ||
|
||
## Потоки | ||
|
||
Поток данных не что иное, как событие, повторяющеесе во времени. Для начала, можно представить в виде | ||
потока последовательность кликов пользователя: | ||
|
||
![поток]({{ site.url }}/assets/images/stream-base.png){: .center} | ||
|
||
Инициируемые в потоке события можно разделить на три типа: `значение`, `ошибка` и `завершение потока`. | ||
В нашем примере завершением будет закрытие пользователем страницы. Поток может получать бесконечное | ||
количество событий и в то же время, любое единичное событие может быть представлено в виде потока (тот же самый клик). | ||
|
||
Поток выше изображен в виде [марбл-диаграммы](http://rxmarbles.com/), но есть и альтернативный способ | ||
визуализации событий - c помощью ASCII кодировки. RxJS 5 позволяет использовать такие диаграммы | ||
при написании тестов ([Observable.combineLatest.spec](http://reactivex.io/rxjs/test-file/spec-js/observables/combineLatest-spec.js.html#lineNumber7)) | ||
|
||
``` | ||
--a---b-c---d---X---|-> | ||
a, b, c, d события значения | ||
X ошибка | ||
| завершение потока | ||
---> шкала времени | ||
``` | ||
|
||
Помимо *кликов*, веб приложение, как правило, должно уметь оперировать множеством как синхронных, так и асинхронных | ||
событий, каждые из которых, в свою очередь, могут быть однократными и многократными. К асинхронным событиям можно отнести: | ||
- UI события, любое взаимодействие пользователя с интерфейсом | ||
- Запросы к серверу | ||
- События устройства, пуш уведомления, системные нотификации | ||
- [Веб хуки](https://en.wikipedia.org/wiki/Webhook) | ||
|
||
> Асинхронное событие - событие, которое произойдет в какой-либо неопределенный момент в будущем | ||
Есть и другие варианты объяснения асинхронности, например, с использованием [пиццы и World of Warcraft](http://stackoverflow.com/a/4560233/4486673) | ||
|
||
Повторение любого из вышеперичисленных асинхронных событий довольно просто представить в формате потока данных за промежуток времени. | ||
Сложнее мыслить *реактивно* в отношении синхронных, последовательных событий, которыми является, например, `массив` | ||
|
||
{% highlight javascript %} | ||
[1,2,3,4,5].forEach(item => { | ||
item; // событие-значение | ||
}); | ||
{% endhighlight %} | ||
|
||
Перебрав массив из 5 элементов, мы определили синхронный поток, в котором были инициированы 5 событий *значение* | ||
и одно *завершение потока*. Процесс аналогичен сессии пользователя, который 5 раз кликнул по кнопке и закрыл страницу. | ||
Таким же образом в роли последовательного потока может выступать не только массив, но любой итерабельной объект: `Set`, `Map`, `String` и т.д. | ||
|
||
Если посмотреть еще шире, можно переложить эту же концепцию на реальную жизнь и представить в виде потока такие | ||
синхронные события как сон, чтение книги, поездка в автобусе и асинхронные - момент закипания чайника, заказ еды на дом. Конечно, | ||
синхронность или асинхронность того или иного события можно обсуждать и это весьма интересно, но тем не менее, | ||
становится понятно, что представить в виде потока можно все, что угодно. И это подводит нас к главной мантре реактивного программирования: | ||
|
||
![Все - поток]({{ site.url }}/assets/images/stream-dog.jpeg){: .center } | ||
|
||
## Чем обрабатывать потоки? | ||
|
||
Как мы выяснили, наше приложение - инкубатор всевозможных потоков. Давайте поверхностно рассмотрим средства их обработки. | ||
Далее речь пойдет об асинхронных событиях, про варианты обработки синхронных событий можно посмотреть здесь: | ||
[Lodash](https://lodash.com/docs/), [Ramda](http://ramdajs.com/docs/) | ||
|
||
- [EventTarget](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget) интерфейс обработки различных UI событий в javascript. | ||
Клик пользователя, например, можно поймать следующим образом: | ||
|
||
{% highlight javascript %} | ||
document.getElementById('button').addEventListener('click', event => { | ||
// обработка | ||
}); | ||
{% endhighlight %}{: .margin-no_top} | ||
|
||
- [EventEmitter](https://nodejs.org/api/events.html) используется при построении асинхронно-событийной архитектуры в Node.js | ||
|
||
{% highlight javascript %} | ||
const emitter = new EventEmitter(); | ||
|
||
emitter.on('event', data => { | ||
// обработка | ||
}); | ||
|
||
emitter.emit('event', data); // пуш события | ||
{% endhighlight %}{: .margin-no_top} | ||
|
||
- [Функции обратного вызова](http://callbackhell.com/) как вариант обработки однократного асинхронного события, например, чтения файла | ||
{% highlight javascript %} | ||
const cb = function(err, data) { | ||
if (err) { | ||
// событие-ошибка | ||
} | ||
|
||
// событие-значения | ||
} | ||
|
||
fs.readFile('data.txt', cb); | ||
{% endhighlight %}{: .margin-no_top} | ||
|
||
- [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) так же используются | ||
для однократных асинхронных вычислений | ||
{% highlight javascript %} | ||
const request = new Promise((resolve, reject) => { | ||
// имитация запроса к серверу | ||
window.setTimeout(() => { resolve(true); }, 3000); | ||
}); | ||
|
||
request | ||
.then(response => { ... }) // событие-значения | ||
.catch(err => { ... }) // событие-ошибка | ||
{% endhighlight %}{: .margin-no_top} | ||
|
||
- [Генераторы](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*) - функции с | ||
возможностью приостановить свое выполнение на некоторое время, после чего возобновить вновь. Своего рода имплементация | ||
[корутин](https://en.wikipedia.org/wiki/Coroutine) в javascript, позволяющая писать асинхронный код в синхронном стиле | ||
{% highlight javascript %} | ||
function request(url) { | ||
ajaxCall(url, response => { it.next(response); }); | ||
} | ||
|
||
function *main() { | ||
const result = yield request('http://some.url'); | ||
const data = JSON.parse(result); // событие-значение | ||
} | ||
|
||
const it = main(); | ||
it.next(); | ||
{% endhighlight %}{: .margin-no_top} | ||
|
||
- [Web sockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) и [Web workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) | ||
|
||
И экспериментальные, еще не принятые на сегодняшний день в стандарт инструменты, которые, тем не менее, | ||
можно использовать посредством [Babel полифиллов](https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-regenerator): | ||
|
||
- [Async functions](https://github.com/tc39/ecmascript-asyncawait) были предложены как часть стандарта ES2016. | ||
В данный момент фича находится на завершающем этапе принятия - Stage 4. Подробно с асинхронными функциями можно | ||
ознакомиться в соответствующем [предложении](https://tc39.github.io/ecmascript-asyncawait/) | ||
- [Async generators](https://github.com/jhusain/asyncgenerator) изначально были задуманы для реализации обработки многократных | ||
асинхронных событий. В данный момент фича получила более компактное описание на [Stage 3](https://github.com/tc39/proposal-async-iteration), | ||
но, возможно, будет реализована в виде [ECMAScript Observable](https://github.com/tc39/proposal-observable) - имплементации | ||
Observable для стандарта ES2016 (теме Observable посвещена следующая статья из этой серии) | ||
|
||
## Причем тут RxJS? | ||
Было бы удобно иметь единый интерфейс взаимодействия с любым средством событийной обработки. И такой интерфейс | ||
предоставляет бибилиотека [RxJS](https://github.com/ReactiveX/rxjs) (Reactive Extensions for Javascript). | ||
|
||
![rxjs-logo]({{ site.url }}/assets/images/rx-logo.png){: .center .rx-logo} | ||
|
||
С ее помощью возможно комбинировать между собой потоки различных типов данных, преобразовывать их, отменять, приводить к определенному типу, | ||
и многое другое. Об этом мы поговорим в следующей статье, | ||
в которой рассмотрим `Observable` - сущность, которую RxJS использует в качестве потока данных. | ||
|
||
## Почитать и посмотреть по теме | ||
- [The introduction to Reactive Programming you've been missing](https://gist.github.com/staltz/868e7e9bc2a7b8c1f754) | ||
- [Основы работы с событиями](https://learn.javascript.ru/events-and-interfaces) | ||
- [Asynchronous Programming: The End of The Loop](https://egghead.io/courses/mastering-asynchronous-programming-the-end-of-the-loop) | ||
- [The Basics Of ES6 Generators](https://davidwalsh.name/es6-generators) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
@mixin image-resize($width) { | ||
height: auto; | ||
max-width: $width; | ||
} | ||
|
||
.center { | ||
margin: 0 auto; | ||
display: block; | ||
} | ||
|
||
.margin-no_top { | ||
margin-top: 0 !important; | ||
} | ||
|
||
.rx-logo { | ||
@include image-resize(200px); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.