React开发进阶redux saga使用原理详解
作者:空山与新雨 发布时间:2023-08-06 09:08:33
前言
工作中使用了redux-saga这个redux中间件,如果不明白内部原理使用起来会让人摸不着头脑,阅读源码后特意对其原理做下总结。
redux的特点
一个标准、管理应用副作用的redux中间件
实现切面编程方式
声明式的编写方式
订阅发布的设计模式
优点:
把异步操作转移到单独 saga文件中,而不是糅杂在action或者component中;
dispatch的参数保持为纯粹的action而不是thunk function;
大量的saga辅助函数和effect创建器减少了开发者的开发成本;
灵活的串行或并行能够实现复杂的异步流程。
分析原理
先举个实践的例子
import { createStore, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import thunk from 'redux-thunk';
import { put, takeEvery, delay, call, select } from 'redux-saga/effects';
const reducer = (state = 0, action) => {
switch (action.type) {
case 'put':
return state + action.payload;
default:
return state;
}
};
const sagaMiddleware = createSagaMiddleware()
export const store = createStore(reducer, applyMiddleware(sagaMiddleware, thunk));
function* main() {
// 工具函数 delay 阻塞1s
var start = Date.now();
yield delay(1000);
console.log(Date.now() - start);// 1秒多
// put 类似于 dispatch
yield put({ type: 'put' , payload:10});
// takeEvery 不阻塞程序
yield takeEvery('takeEvery111', function ({ type, payload }) {
console.log('takeEvery', type, payload); // yield put({ type: 'takeEvery111' , payload:10}); 触发
});
// select 获取state中的数据
const state = yield select((state) => state);
console.log(state); // 10
// call 阻塞程序
yield call(function* () { // 阻塞
yield delay(1000);
});
console.log(Date.now() - start);// 2秒多
yield put({ type: 'takeEvery111' , payload:10});
}
sagaMiddleware.run(main);
依次打印出如下结果:
1001
10
2004
takeEvery takeEvery111 10
1. 自动执行Generator
从执行结果来看,这个main函数能自动按顺序执行说明在redux-saga的程序代码中有自动执行gen的机制,其实源码就是./internal/proc.js
文件中,通过函数之间循环调用的方式执行这个gen函数。
这样的自动执行机制在generator中是比较常见的,比如co模块就具有这样的功能,其实现巧妙却不复杂,如下例子:
function makePromisify(source) {
if (source.then && typeof source.then === "function") return source
return Promise.resolve(source)
}
function run(generatorFunc) {
let it = generatorFunc()
let result = it.next()
return new Promise((resolve, reject) => {
const next = function (result) {
if (result.done) {
resolve(result.value)
}
//保证返回的是一个promise
result.value = makePromisify(result.value)
result.value.then(res => {
//将promise的返回值res传入iterator迭代器的next方法中,作为yield后面表达式的返回值
//it.next将停止的yield继续执行到下一个yield,返回的result是一个value,done属性组成的对象
let result = it.next(res)
//递归执行next函数
next(result)
}).catch(err => {
reject(err)
})
}
next(result)
})
}
2. 发布订阅模式
我们看到takeEvery是可以拦截到{type: 'takeEvery111'}
这个action,说明在redux-saga
内部有类似发布订阅on/trigger
这样的机制,通过阅读源码我们发现,内部通过channel
这个东西来做发布订阅的处理;在./internal/channel.js
就有这样的源码:
put(input) {
const takers = (currentTakers = nextTakers)
for (let i = 0, len = takers.length; i < len; i++) {
const taker = takers[i]
// 如果take匹配到, 执行它
if (taker[MATCH](input)) {
taker.cancel()
taker(input) // 发布
}
}
},
take(cb, matcher = matchers.wildcard) {
cb[MATCH] = matcher
ensureCanMutateNextTakers()
nextTakers.push(cb) // 订阅
},
3. put, takeEvery, delay, call返回effect
put执行并不是直接dispatch一个action,而是通过yield向redux-saga内部传递参数(这个参数在redux-saga中叫effect),内部根据这个参数决定具体的执行内容。
在源码中put、fork、call 等是通过 makeEffect 创建了一系列 effect,这个 effect 是一个普通的 js 对象,上面挂载了一些相关的信息,并且把这个effect yield到内部的runEffejct中,然后根据type字段决定真正需要执行的程序过程。
const makeEffect = (type, payload) => ({
[IO]: true,
combinator: false,
type,
payload,
});
来源:https://www.cnblogs.com/walkermag/p/16913838.html
猜你喜欢
- 在写完前面“模块化”相关的文章后,感觉试图用“模块化”本身去讲什么是“模块化”真是不容易讲得清。相信大家都多多少少能理解什么是“模块化”,但
- 一般情况下,导出超时可能都是以下三种情况:一、sql语句复杂,查询时间过长;二、处理查询后数据逻辑冗余;三、数据量过大导致响应超时。接下来分
- 近段时间由于修改一个ASP程序(有SQL注入漏洞),在网上找了很多相关的一些防范办法,都不近人意,所以我将现在网上的一些方法综合改良了一下,
- 实现一个AuditLog的功能,是B/S结构专案。 每个用户可以登录系统,在程序中操作数据(添加,更新和删除)需要实现记录操作跟踪。是谁添加
- 一、JSP EL语言定义 E L(Expression
- 在VBScript中有Filter这个函数可以用来对数组进行过滤,并返回原数组的一个子集数组。语法说明: 引用内容Filter 函
- 介绍两个关键的CSS <style media="print">  
- 假设现有一张人员表(表名:Person),若想将姓名、身份证号、住址这三个字段完全相同的记录查找出来,使用1: SELECT p
- 本文实例讲述了php中正则替换函数ereg_replace用法。分享给大家供大家参考。具体如下:下面的实例是利用php 正则替换函数 ere
- 建立池连接可以显著提高应用程序的性能和可缩放性。SQL Server .NET Framework 数据提供程序自动为 ADO.NET 客户
- ajax.html <html><head> <met
- import webbrowser as webimport timeimport oscount=0while count<10:&
- 在网页中,我们经常需要引用大量的javascript和css文件,在加上许多javascript库都包含debug版和经过压缩的releas
- 本文给出了MySQL数据库中定义外键的必要性、具体的定义步骤和相关的一些基本操作,供大家参考!定义数据表假如某个电脑生产商,它的数据库中保存
- 软件环境: 1、操作系统:Windows 2000 Server 2、数 据 库:Oracle 8i R2 (8.1.7) for NT 企
- InnoDB给MySQL提供了具有提交,回滚和崩溃恢复能力的事务安全(ACID兼容)存储引擎。InnoDB锁定在行级并且也在SELECT语句
- 这几天不是很忙,就找了些拖动布局方面的资料看看,也学着写了个拖动布局的效果,没想到花了好多时间,七拼八凑,总算是把这个效果写出来了。哎!还是
- 本文实例讲述了go语言睡眠排序算法。分享给大家供大家参考。具体分析如下:睡眠排序算法是一个天才程序员发明的,想法很简单,就是针对数组里的不同
- 本文为大家分享了php运行环境搭建安装图文教程,供大家参考,具体内容如下安装apache:1,不要安装到有中文的目录中:2,尽量将apach
- 内容摘要:统计在线人数的方法很多,可以使用Application来统计在线人数,也可以使用IP来统计在线人数。各有优点。本文介绍了通过判断S