Сага о yield

Скрытые возможности

Нажми пробел чтобы продолжить

Стрелка вправо — для быстрой промотки

Веб-сервис МойМеханик

Автомеханик приедет к вам домой и на работу

Redux + Riot.js

3 месяца

Agile

3 программиста

Чем хорош Flux

3. Многоразовые компоненты

2. Просто отладить

1. Легко понять

Как работает

страница
корзины ?


// on button click
function onCancel(){

  store.dispatch({
    type: 'ORDER_UPDATE_CANCEL_REQUESTED',
    orderId
  })
}

// on button click
function onSubmit(){

  updateOrder({
    orderId,
    onSuccess: updateQuote,
  })
}
function updateQuote(orderId){

  store.dispatch({
    type: 'INSTANT_QUOTE_REQUESTED',
    orderId
  })

  let request = fetchAPI('/quote/update', {
    userId,
    orderId
  })

  // ...
}

request.then(function(data){
  if (data.status == 4000005){

    store.dispatch({type: 'USER_LOGOUT'})

    store.dispatch({type: 'AUTH_REQUESTED'})
  }
})

Готово !

А где работа с <form></form>?

Где fetchOrder() ?

Где window.location = '/payment' ?

1. Разбит на части и переплетен

Каков код на вкус?

2. Непонятно где начало, где конец

3. Сделать еще одно приложение  ― для мастеров

Хорошие новости!

1. Упаковать сайт в формат виджета для сайтов партнеров

2. Упаковать в PhoneGap приложение

Будущее проекта
прекрасно!

Естественная запись кода

Что делает страница заказа?

1. отобразить прелоадер

2. загрузить заказ с сервера

3. показать форму заказа

4. дождаться ввода пользователя

5. отправить данные на сервер

6. отобразить ошибки

7. repeat until

// 1. отобразить прелоадер
mountPage('preloader-page')
// 2. загрузить заказ с сервера
let response = yield fetch(`/order/${id}`)
// 3. показать форму заказа
let pageChannel = mountPage('order-page')
let order = yield response.json()
store.dispatch({
  type: 'ORDER_FETCHED',
  payload: order
})
// 4. дождаться ввода пользователя
let formData = yield take(pageChannel)
// 5. отправим данные на сервер
let response = yield fetch(`/order/${id}`,{
  method: 'POST',
  body: JSON.stringify(formData),
})
let errors = yield response.json()
if (!errors.length)
  return window.location = '/payment'
// 6. отобразить ошибки
store.dispatch({
  type: 'ERRORS_OCCURRED',
  errors
})
// 7. repeat until
// TODO обернуть код в while(true){}
// Поместить весь код в function*(){}

yield & coroutines

function* runAndWait() {

  console.log('Готов к работе')
  let serverData = yield {
    command: 'waitForServerResponse',
    promise: fetch('/orders'),
  }
  // ...
}
  let userData = yield {
    command: 'waitForUserInput',
  }
  1. Запускаешь
  2. Обрабатываешь события
  3. Останавливаешь

Coroutine
Как аналог процесса

Redux-saga


yield promiseObj
yield take(channel)
let task = yield fork(coroutine)
yield join(task)
yield cancel(task)

Песочница

/catalog

function* runCatalogPage

/cart

function* runCartPage
function* updateOrder

/payment

function* runCatalogPage
function* updateQuote

Исключения ♡ Декораторы


--> function* handleCommonAPIErrors

----> function* runCartPage
------> function* fetchAPI
--------> throw new APIError({code: 500002})
function decorate(coroutine){

  function* wrappedCoroutine(){

    try {
      yield* coroutine()
    } catch(error) {
      // handle error
    }
  }
  return wrappedCoroutine
}

const wrappedRunCartPage = decorate(runCartPage)

OrderNotFound

try {
  yield* runPage()
} catch(exception) {

  if (exception instanceof OrderNotFound){
    mountPage('order-not-found')
  }
  // ...

LoginRequired

try {
  yield* runPage()
} catch(exception) {

  if (exception instanceof LoginRequired){
    window.location = '/signin'
  }
  // ...
}

Что-то пошло не так

try {
  yield* runPage(...args)

} catch(exception) {

  Raven.captureException(exception)

  mountPage('error-page')
}

Шаблоны без сайд-эффектов

Store

React

== Model

== View + Controller

Store

React

Coroutine

select

channel.put

View

Controller

Что это дало проекту МойМеханик ?

  1. способность наращивать функционал

  2. в коде легко ориентироваться

  3. меньше бойлерплейта

  4. Hot Module Replacement

С чего начать ?

  1. Еще примеры кода: slides.com/pelid80/redux-saga
  2. Примеры кода на GitHub: pelid/redux-saga-demo
  3. Документация по redux-saga
  4. Заменить роутер на проекте

Ищу людей в OpenSource проект

Напишите мне pelid80@gmail.com

Спасибо!

Какие есть вопросы?

Автор доклада: Евгений Евсеев

CTO веб-сервиса МойМеханик.рф

email pelid80@gmail.com

skype evseev.evgeny

Сага о yield

By Evgeny Evseev

Сага о yield

  • 1,183