博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
redux-saga 原理浅析
阅读量:4086 次
发布时间:2019-05-25

本文共 3568 字,大约阅读时间需要 11 分钟。

前言

笔者最近在做一些后台项目,使用的是,其使用了处理异步数据流,本文将对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创建器,如callputtake等,已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);  }} 复制代码

看到这里我们可以发现,需要我们做的就是不断的完善nextWithYieldType这个函数,当完成了putforktakeEvery对应的逻辑后,一个具备基本功能的redux-saga就诞生啦,笔者就不在赘述这些功能的实现了。最后,你可以查看这里:,这是笔者实现的一个简易版的redux-saga,希望对你有所帮助。


全文完。

作者:菜菜_张
链接:https://juejin.im/post/5c021f245188252bf829ce26
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的文章
ES6这些就够了
查看>>
微信小程序:支付系列专辑(开发指南+精品Demo)
查看>>
iOS应用间相互跳转
查看>>
iOS开发之支付宝集成
查看>>
iOS开发 支付之银联支付集成
查看>>
iOS开发支付集成之微信支付
查看>>
浅谈JavaScript--声明提升
查看>>
React非嵌套组件通信
查看>>
Websocket 使用指南
查看>>
浏览器兼容性问题解决方案 · 总结
查看>>
一个很棒的Flutter学习资源列表
查看>>
为什么你应该放弃React老的Context API用新的Context API
查看>>
Flutter 布局控件完结篇
查看>>
Koa2初体验
查看>>
Koa 2 初体验(二)
查看>>
Koa2框架原理解析和实现
查看>>
vue源码系列文章good
查看>>
你不知道的Virtual DOM
查看>>
VUE面试题总结
查看>>
写好JavaScript条件语句的5条守则
查看>>