Brevemente sobre canais redux-saga

Boa tarde, queridos amigos.


Neste artigo, gostaria de descrever o mecanismo dos canais redux-saga o mais simples e conciso possível, usando exemplos próximos de casos reais, espero que isso tenha funcionado para mim.


Então, vamos começar.


Problema com o modelo de relógio e garfo


Suponha que tenhamos um modelo regular de relógio e garfo, da seguinte forma:


import { take, fork } from 'redux-saga/effects' function* watchRequest() { while (true) { const {payload} = yield take('INIT_REQUEST'); // ,     yield fork(makeRequest, payload); } } function* makeRequest(payload) { //   } 

Essa abordagem é ruim porque, ao capturar vários eventos INIT_REQUEST que se seguem, várias execuções makeRequest serão makeRequest , respectivamente. O que, por sua vez, pode levá-los a "correr".


E aqui o mecanismo do canal vem em nosso auxílio.


Os canais têm buffers, ajudando a alinhar os eventos recebidos (por exemplo, INIT_REQUEST ) e organizando sua execução sequencial (por exemplo, makeRequest será executado várias vezes sequencialmente).


Grosso modo, os canais formam uma fila FIFO para execução sequencial.


Classifique por origem do evento:


  • channel - eventos são enfileirados manualmente usando put ;
  • actionChannel - eventos são capturados perto da loja redux;
  • eventChannel - uma fonte de eventos externa, geralmente um soquete da web;

Então, analisaremos brevemente cada um.


Mais no canal


Esses canais geralmente resolvem o problema de comunicação entre sagas. Usado muito raramente. Por exemplo, se você precisar coordenar várias solicitações, iniciando ao mesmo tempo.


 channel([buffer]) 

Ele possui um único argumento de buffer - o buffer acumulado (examinaremos os buffers em mais detalhes abaixo).


Mais sobre actionChannel


É usado com mais frequência quando é necessário responder a eventos do repositório redux.


 actionChannel(pattern, [buffer]) 

São necessários dois argumentos:


  • pattern - o padrão dos eventos desejados, bem como a take ;
  • buffer - buffer acumulativo;

Um breve exemplo de uso:


 import { take, actionChannel, call } from 'redux-saga/effects' function* watchRequest() { const requestChannel = yield actionChannel('INIT_REQUEST') while (true) { const {payload} = yield take(requestChannel); //      yield call(makeRequest, payload); } } function* makeRequest(payload) { //   } 

Mais sobre eventChannel


Geralmente eles resolvem o problema da comunicação através do soquete da web através dele.


 eventChannel(subscribe, [buffer], [matcher]) 

São necessários três argumentos:


  • subscribe é uma função que inicializa uma fonte de eventos externa (no exemplo abaixo, setTimeout). Nos argumentos, um retorno de chamada é chamado emissor, que será chamado quando for necessário enviar dados para o canal a partir da fonte. O retorno deve cancelar a função de inscrição;
  • buffer - buffer acumulativo;
  • matcher - função para filtrar as mensagens recebidas.

Um breve exemplo de uso:


 import { eventChannel, END } from 'redux-saga' import { take, put, call } from 'redux-saga/effects' function initSocketChannel(query) { return eventChannel(emitter => { //     web socket const handshakeTimeoutId = setTimeout(() => { emitter('handshake - ok'); }, 100); const messageTimeoutId = setTimeout(() => { emitter('message'); }, 500); const endTimeoutId = setTimeout(() => { emitter(END); }, 1000); //     return () => { clearTimeout(handshakeTimeoutId); clearTimeout(messageTimeoutId); clearTimeout(endTimeoutId); } } ) } export function* saga() { const chan = yield call(initSocketChannel, query) try { while (true) { const message = yield take(chan); //    END   brake console.log(`socket : ${message}`) } } finally { console.log('socket terminated') } } 

Certamente você notou a presença da constante END - isto é ação, o que significa o fim da comunicação com o canal.


No código fonte, redux-saga é representado da seguinte maneira:


 var CHANNEL_END_TYPE = '@@redux-saga/CHANNEL_END'; var END = { type: CHANNEL_END_TYPE }; var isEnd = function isEnd(a) { return a && a.type === CHANNEL_END_TYPE; }; 

e no código fonte eventChannel vemos o seguinte script


 function eventChannel(subscribe) { … if (isEnd(input)) { close(); return; } ... } 

O que é buffer?


É digno de nota, uma vez que cada canal possui um buffer básico e, com ele, uma fila de processamento é formada.


Exemplo de criação de um buffer:


 import { buffers } from 'redux-saga' const buffer = buffers.sliding(5); 

buffers são uma instância de uma fábrica para a criação de buffers com estratégias diferentes.


Apenas 5 estratégias, métodos correspondem a eles:


  • buffers.none() - sem buffer, novas mensagens serão perdidas se não houver participantes pendentes;
  • buffers.fixed(limit) - novas mensagens serão armazenadas em buffer até o limite. Um erro de estouro resultará em uma exceção. O limite padrão é 10;
  • buffers.expanding(initialSize) - como fixo, mas o estouro fará com que o buffer se expanda dinamicamente;
  • buffers.dropping(limit) é o mesmo que fixo, mas o excesso descartará silenciosamente as mensagens;
  • buffers.sliding(limit) é o mesmo que fixo, mas o estouro adicionará uma nova mensagem ao final e excluirá a mensagem mais antiga do buffer.

Em vez de desligar


Assim, examinamos por que o mecanismo de canal foi inventado e em que tarefas práticas são usadas.


Espero que, depois de ler a idéia geral, o mundo tenha se tornado um pouco mais fácil.

Source: https://habr.com/ru/post/pt432070/


All Articles