Skip to main content

Concurrency and Racing

Promise Saga replicates the functionality of the well-known Promise.all and Promise.race for sagas.

While having a simple getPokemonData saga to test:

export const getPokemonData = createSaga(async function(pokemon: string) {
const resp = await this.fetch(`https://pokeapi.co/api/v2/pokemon/${pokemon}`);
const data: PokemonData = await resp.json();
return data;
});

You can load many Pokémon concurrently with the all effect:

export const fetchAllPokemons = createSaga(async function() {
const [pikachu, raichu] = await this.all([
getPokemonData('pikachu'),
getPokemonData('raichu'),
]);
console.log({pikachu, raichu});
});

Use the race effect to finish one of the sagas and cancel the others with internal fetch requests:

export const startPokemonsRace = createSaga(async function(timeout: number, withCancel: boolean) {
const [pikachu, raichu] = await this.race([
getPokemonData('pikachu'),
getPokemonData('raichu'),
]);
console.log({pikachu, raichu});
});

Use delay and take within race to perform a timeout for sagas racing:

import {createAction} from '@reduxjs/toolkit';

export const cancelAction = createAction('action/cancel');

export const startPokemonsRace = createSaga(async function(timeout: number, withCancel: boolean) {
const [pikachu, raichu] = await this.race([
getPokemonData('pikachu'),
getPokemonData('raichu'),
this.delay(500), // automatic cancel in 500 ms
this.take(cancelAction), // manual cancel on action dispatch
]);
console.log({pikachu, raichu});
});