温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

redux-saga原理是什么

发布时间:2020-12-08 14:00:51 来源:亿速云 阅读:132 作者:小新 栏目:web开发

这篇文章将为大家详细讲解有关redux-saga原理是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

Generator函数的自动流程控制

在redux-saga中,saga是指一些长时操作,用generator函数表示。generator函数的强大之处在于其可以手动的暂停、恢复执行,且可以与函数体外进行数据交互,看如下例子:

function *gen() {
  const a = yield 'hello';
  console.log(a);
}
cont g = gen();
g.next(); // { value: 'hello', done: false }
setTimeout(() => g.next('hi'), 1000)  // 此时 a => 'hi'   一秒后打印‘hi'

可以看出来genrator函数何时进行下一步操作完全取决于外部的调度时机,且其内部执行状态也由外部的输入决定,这使得generator函数可以很方便的做异步流程控制。举个例子,我们首先读取一个文件的内容作为查询参数,然后请求一个查询接口并把返回的内容打印出来:

function getParams(file) {
  return new Promise(resolve => {
    fs.readFile(file, (err, data) => {
      resolve(data)
    })
  })
}
function getContent(params) {
  //  request返回promise
  return request(params)
}
function *gen() {
  const params = yield getParams('config.json');
  const content = yield getContent(params);
  console.log(content);
}

我们可以手动控制gen函数的执行:

const g = gen();
g.next().value.then(params => {
  g.next(params).value.then(content => {
    g.next(content);
  })
})

以上可以达到我们的目的,但是过于繁琐,我们想要的是generator函数可以自动的执行,可以写一个简易的自动执行函数如下:

function genRun(gen) {
  const g = gen();
  next();
  function next(err, pre) {
    let temp;
    (err === null) && (temp = g.next(pre));
    (err !== null) && (temp = g.throw(pre));

    if(!temp.done) {
      nextWithYieldType(temp.value, next);
    }
  }
}
function nextWithYieldType(value, next) {
  if(isPromise(value)) {
    value
      .then(success => next(null, success))
      .catch(error => next(error))
  } 
}
genRun(gen);

此时generator函数便可以自动执行,事实上我们可以发现,generator的内部状态完全是由nextWithYieldType决定的,我们可以根据yield的类型执行不同的处理逻辑。

Effect

事实上sagaMiddleware.run(saga)可以类似看做genRun(saga),而saga是由一个个的effect组成的,那么effect是什么?redux-saga官网的解释:一个 effect 就是一个 Plain Object JavaScript 对象,包含一些将被 saga middleware 执行的指令。redux-saga提供了很多Effect创建器,如call、put、take等,已call为例:

function saga*() {
  const result = yield call(genPromise);
  console.log(result);
}

call(genPromise)生成的就是一个effect,它可能类似如下:

{
  isEffect: true,
  type: 'CALL',
  fn: genPromise
}

事实上effect只表明了意图,而实际的行为由类似于上文的nextWithYieldType完成,例如:

function nextWithYieldType(value, next) {
  ...
  if(isCallEffect(value)) {
    value.fn(). then(success => next(null, success)).catch(error => next(error))  
  } 
}

当genPromise函数返回的promise被resolve后便会打印出结果。

生产者与消费者

观察下面的例子

function *saga() {
  yield take('TEST');
  console.log('test...');
}

sagaMiddleware.run(test);

saga会在take('TEST')处阻塞,只有执行了dispatch({type: 'TEST'})后saga才能继续运行(注意:此时的dispatch方法是经过sagaMiddleware包装过的)。这给我们的感觉似乎很像是take是一个生产者,在等待disaptch的消费,事实上take只是一个Effect生成器,具体的处理逻辑依然是在nextWithYieldType完成的,类似于:

function nextWithYieldType(value, next) {
  ...
  // take('TEST')生成的effect简单的认为是  {isEffect: true, type: 'TAKE', name: 'TEST'}
  if(isTakeEffect(value)) {
    channel.take({pattern: value.name, cb: params => next(null, params)})  
  } 
}

channel是一个任务生成器,它有两个方法:take生成任务,put消费任务:

function channel() {
  /*
    task = {
      pattern,
      cb
    }
  */
  let _task = null;

  function take(task) {
    _task = task;
  }

  function put(pattern, args) {
    if(!_task) return;
    if(pattern == _task.pattern) _task.cb.call(null, args);
  }

  return {
    take,
    put
  }
}

显然任务是在执行dispatch的时候被消费掉的,这个工作是在sagaMiddleware中做的,类似于如下:

const sagaMiddleware = store => {
  return next => action => {
    next(action);
    
    const { type, ...payload } = action;
    channel.put(type, payload);
  }
}

关于redux-saga原理是什么就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI