Асинхронные этюды

или

Архитектурные подходы для асинхронных операций в современном фронтенде




Ефремов Алексей

Зачем?

Асинхронность  это  боль...
pain

Бусю печалит

Асинхронность

Если не уметь ее готовить

Выход

правильная архитектура приложения

solution

Как выбрать?

question
Поспать...
Поесть...
Пошалить...

Муки выбора

1. Vanila JS


						

						fetch('/api/user').then(d => d.json()).then(data => {
							const name = document.getElementById('name');
							if (name) {
								name.innerText = data.name;
							}
							const status = document.getElementById('status');
							if (status) {
								status.innerText = data.status;
							}
						});
					

2. React with local state


					class User extends React.Component {
						state = {};
						componentDidMount() {
							fetch('/api/user')
								.then(d => d.json())
								.then(data => this.setState(data));
						}
						render() {
							return (
								
{this.state.name} {this.state.status}
); } }

3. Backbone


					const User = Backbone.Model.extend({
						urlRoot: '/api/user',
						defaults: { name: '', status: '' }
					});

					const View = Backbone.View.extend({
						model: User,
						initialize(options) {
							this.listenTo(this.model, 'change', this.render);
							this.model.fetch();
						}
						render() {
							this.$el.html(`
								
${this.model.get('name')} ${this.model.get('status')}
`); } });

4. React + Redux


						import { connect } from 'react-redux';
						import { fetchUser } from './action'

						class User extends React.Component {
							componentDidMount() { this.props.load(); }
							render() {
								const { name, status } = this.props;
								return (
{name}{status}
); } } const UserSmart = connect(state => state.user, dispatch => ({ load: () => dispatch(fetchUser()) }))

						export function fetchUser() {
							return function(dispatch) {
								dispatch({ type: 'FETCH_USER' });
								return fetch('/api/user').then(d => d.json())
									.then(
										data => dispatch({ type: 'SUCCESS_USER', data }),
										error => dispatch({ type: 'ERROR_USER', error })
									);
							}
						}
					

						function rootReducer(state, action) {
							if (action.type === 'FETCH_USER') {
								return { ...state, user: { loading: true }};
							} else if (action.type === 'SUCCESS_USER') {
								return { ...state, user: { loading: false, data: action.data }};
							} else if (action.type === 'ERROR_USER') {
								return { ...state, user:  { loading: false, error: action.error }};
							} else {
								return state;
							}
						}
						import thunk from 'redux-thunk';
						import { createStore, applyMiddleware } from 'redux';
						const store = createStore(rootReducer, applyMiddleware(thunk));
						

5. React + redux-api

redux-api

						import { connect } from 'react-redux';
						import { rest } from './store';

						class User extends React.Component {
							componentDidMount() { this.props.load(); }
							render() {
								const { data, error, loading } = this.props;
								if (loading) {
									return 
Loading
} else if (error) { return
Error: {error.message}
} else { const data = { name, status }; return (
{name}{status}
); } } } const UserSmart = connect(state => state.user, dispatch => ({ load: () => dispatch(rest.action.user()) }))
redux-api

						import reduxApi from 'redux-api';
						import adapterFetch from 'redux-api/lib/adapters/fetch';
						import thunk from 'redux-thunk';
						import { createStore, applyMiddleware } from 'redux';

						/* redux-api initialization */
						export const rest = reduxApi({ user: '/api/user' });
						rest.use('fetch', adapterFetch(fetch));

						/* integrate redux-api to redux flow */
						export const store = createStore(rest.reducer, applyMiddleware(thunk));
						

Jsconf Iceland 2018 link

Dan Abramov: Beyond React 16

6. React + react-async-decorator

react-async-decorator

					import { asyncClass, initFetchers } from 'react-async-decorator';
					const createFetcher = initFetchers();
					const fetcher = createFetcher(() =>
						fetch('/api/user').then(d => d.json()));

					@asyncClass(fetcher)
					class User extends React.Component {
						render() {
							const { name, status } = fetcher.get();
							return (
								
{name} {status}
); } }

Выводы

Вопросы к Бусе

и докладчику

Спасибо за внимание