Brevemente sobre los canales redux-saga

Buenas tardes, queridos amigos.


En este artículo me gustaría describir el mecanismo de los canales de redux-saga de la manera más simple y concisa posible, usando ejemplos cercanos a casos reales, espero que esto haya funcionado para mí.


Entonces comencemos.


Problema con el modelo de reloj y tenedor


Supongamos que tenemos un modelo regular de reloj y horquilla, de la siguiente 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) { //   } 

Este enfoque es malo porque al capturar varios eventos INIT_REQUEST que siguen uno tras otro, se makeRequest varias ejecuciones de makeRequest , respectivamente. Lo que a su vez puede hacer que "compitan".


Y aquí el mecanismo del canal viene en nuestra ayuda.


Los canales tienen buffers, lo que ayuda a alinear los eventos entrantes (por ejemplo, INIT_REQUEST ) y organizar su ejecución secuencial (por ejemplo, makeRequest se ejecutará varias veces secuencialmente).


En términos generales, los canales forman una cola FIFO para la ejecución secuencial.


Clasificar por fuente de evento:


  • channel : los eventos se ponen en cola manualmente usando put ;
  • actionChannel : los eventos se capturan cerca de la tienda redux;
  • eventChannel : un origen de eventos externo, con mayor frecuencia un socket web;

Entonces, analizaremos brevemente cada uno.


Más en el canal


Tales canales suelen resolver el problema de comunicación entre sagas. Usado muy raramente. Por ejemplo, si necesita coordinar múltiples solicitudes comenzando al mismo tiempo.


 channel([buffer]) 

Tiene un único argumento de buffer : el búfer de acumulación (examinaremos los búferes con más detalle a continuación).


Más sobre actionChannel


Se usa con mayor frecuencia cuando es necesario responder a eventos de la tienda redux.


 actionChannel(pattern, [buffer]) 

Se necesitan dos argumentos:


  • pattern : el patrón de los eventos deseados, así como la take ;
  • buffer - buffer acumulación;

Un breve ejemplo 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) { //   } 

Más sobre eventChannel


Por lo general, resuelven el problema de comunicación a través del socket web a través de él.


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

Se necesitan tres argumentos:


  • subscribe es una función que inicializa un origen de eventos externo (en el ejemplo a continuación, setTimeout). En los argumentos, una devolución de llamada se llama emisor, que se llamará cuando sea necesario enviar datos al canal desde la fuente. La función de devolución debe darse de baja;
  • buffer - buffer acumulación;
  • matcher - función para filtrar mensajes entrantes.

Un breve ejemplo 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') } } 

Seguramente notó la presencia de la constante END : esto es acción, lo que significa el final de la comunicación con el canal.


En el código fuente, redux-saga se representa de la siguiente manera:


 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; }; 

y en el código fuente eventChannel vemos el siguiente script


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

¿Qué es el búfer?


Es de destacar, ya que cada canal tiene un búfer base, y con él, se forma una cola para el procesamiento.


Ejemplo de creación de un búfer:


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

buffers son una instancia de una fábrica para crear buffers con diferentes estrategias.


Solo 5 estrategias, los métodos corresponden a ellas:


  • buffers.none() : sin almacenamiento en búfer, se perderán nuevos mensajes si no hay participantes pendientes;
  • buffers.fixed(limit) : los mensajes nuevos se almacenarán en el límite. Un error de desbordamiento dará como resultado una excepción. El límite predeterminado es 10;
  • buffers.expanding(initialSize) : como fijo, pero el desbordamiento hará que el búfer se expanda dinámicamente;
  • buffers.dropping(limit) es lo mismo que fijo, pero el desbordamiento descartará silenciosamente los mensajes;
  • buffers.sliding(limit) es lo mismo que fijo, pero el desbordamiento agregará un nuevo mensaje al final y eliminará el mensaje más antiguo en el búfer.

En lugar de cerrar


Entonces, examinamos por qué se inventó el mecanismo del canal y en qué tareas prácticas se utilizan.


Espero después de leer la idea general y el mundo se ha vuelto un poco más fácil.

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


All Articles