Implementation of Redux Saga

Time:2020-9-27

redux-sagaIs a library used to manage side effects (side effects, such as asynchronous access to data, access to browser cache, etc.), its goal is to make side effects management easier, execution more efficient, testing simpler, and handling failures easier.

AsreduxThe middleware of,redux-sagaProvides more elegant handling of asynchronyactionThe way to do it,redux-sagaIt is determined by the generator functionsuspendimplementdelayorcancelAnd so on,
A saga is like a single thread in an application that handles side effects alone.

Using Redux saga in Redux

import { createStore, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'

import reducer from './reducers'
import mySaga from './sagas'

// create the saga middleware
const sagaMiddleware = createSagaMiddleware()
// mount it on the Store
const store = createStore(reducer,applyMiddleware(sagaMiddleware))

// then run the saga
sagaMiddleware.run(mySaga)

// render the application

Middleware API

createSagaMiddleware

createSagaMiddlewareThe purpose of the function is to createsagaMiddlewareMiddleware, and we also know thatsagaMiddlewareFunction boundrunmethod

function createSagaMiddleware(){
  return function sagaMiddleware({dispatch,getState}){
    //Binding the run function to sagamiddleware
    sagaMiddleware.run = function(generator){}
    //Middleware function
    return (next) => (action) => {
      next(action);
    }
  }
}

middleware.run

sagaMiddleware.run = function (generator, callback) {
  //Judge whether the generator is a function and return the execution result or itself
  const iterator = typeof generator === "function" ? generator() : generator;
  //The next function determines the next action
  function next(action){
    const { value: effect, done } = iterator.next();
    //If the generator completes, the callback function is executed
    if(done){
      callback && callback();
      return;
    }
    //If effect is a generator
    if (typeof effect.next === "function"){
      run(effect,next);
    }
    //If the effect is a promise, continue to execute next after the promise ends
    if (effect instanceof Promise){
       effect.then(next)
    }
  }
  next();
}

Effect Creator

redux-sagaIt can be seen as one by oneeffectIt is composed of,effectRepresents the instruction executed each timeeffects.jsFiles are used to createeffect

take

takeFunction can blockgeneratorOnly in middlewareactionThis can be understood as an operation of publish and subscribe, which can be created internallychannelFunction is used to create a publish subscriber:

function createChannel() {
  let listener = {};
  let subscribe = (actionType, callback) => listener[actionType] = callback;
  let publish = (action) => {
    if (!listener[action.type]) return;
    let actionFn = listener[action.type];
    delete listener[action.type];
    actionFn(action);
  }
  return { subscribe, publish };
}
const channel = createChannel();
...
return (next) => (action) => {
  channel.publish (action); // the middleware dispatches each action action action
  next(action);
}
...

effectsFiletakeFunction, export and declaretypeType:

// effects.js
export function take(actionType){
  return {
    type:"TAKE",
    actionType
  }
}

staynextFunction, judgeeffectType, and then subscribeactionType, and the nextnextThe operation is passed to the subscription function, which is captured in the middleware functionactionTo trigger the next function execution

switch (effect.type) {
  case "TAKE":
    channel.subscribe(effect.actionType,next);
    break; 
}

put

putMethod executionactionOperation, which is returned directly in the effect functionaction,nextIn the functiondispatch

// effects.js
export function put(action){
  return {
    type:"PUT",
    action
  }
}
case "PUT":
  dispatch(effect.action);
  next(effect.action);
  break;

fork

effectsFunctionfork

// effects.js
export function fork(task) {
  return {
    type:"FORK",
    task
  }
}

staynextIntercepted inFORKType,taskIt could be ageneratorFunction, so pass torunMethod execution,
And keep itforkTask, which is convenient for canceling the task later

case "FORK":
  let forkTask = effect.task();
  sagaMiddleware.run(forkTask);
  next(forkTask);
  break;

cancel

generatorCan be passed throughreturnMethod to terminate the execution of the task, so we can get to the frontforkPreservedgeneratorTo terminate:

// effects.js
export function cancel(task) {
  return {
    type:"CANCEL",
    task
  }
}
case "CANCEL":
  effect.task.return('over')
  break;

takeEvery

takeEveryCan be understood in pairsforkPackage, withwhileMonitor each task:

//effects.js
export function* takeEvery(actionType,task) {
  yield fork(function* (){
    while(true){
      yield take(actionType);
      yield task();
    }
  })
}

call

callMethod to accept the promise function and execute:

//effects.js
export function call(fn,...args) {
  return {
    type:"CALL",
    fn,
    args
  }
}

So in thenextIf it iscallType is executed after promise endsnext

case "CALL":
  effect.fn(...effect.args).then(next)
  break;

cps

callMethod to accept the callback function and execute:

//effects.js
export function cps(fn,...args) {
  return {
    type:"CPS",
    fn,
    args
  }
}
case "CPS":
  effect.fn(...effect.args,next);
  break;

all

allMethods need to wait for allgeneratorThe function can only be executed after it has been executed

//effects.js
export function all(fns) {
  return {
    type:"ALL",
    fns
  }
}
/*
*@ params CB [function] callback function
*@ params total [number] execution quantity
*/
function times(cb, total) {
  let index = 0;
  return () => {
    index++;
    if (index >= total) {
      cb && cb();
    }
  }
}

...
case "ALL":
  const total = effect.fns.length;
  const over = times(next, total);
  effect.fns.forEach(fn => run(fn, over))
  break;
...

Recommended Today

Openkruise: cloud native deployment base of Alibaba double 11 full link application

Introduction:Kruise is a homonym of cruise, ‘k’ for kubernetes, which means navigation and automatic patrol of applications on kubernetes. It is full of Alibaba’s best practices in large-scale application deployment, release and management for many years, as well as the precipitation of the demand of Alibaba cloud kubernetes for thousands of customers. Source|Alibaba cloud official […]