版权声明:如需转载请著明出处 https://blog.csdn.net/qq_37653449/article/details/85563013
fork 和 takeEvery
takeEvery 的作用是每次put 动作执行的的时候 都去调用worker
以下代码可以直接在浏览器运行,执行步骤在代码中做了注释
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<button id="test">
Clickme
</button>
<div id="result">
</div>
<script>
const $btn = document.querySelector('#test');
const $result = document.querySelector('#result');
function channel() {
let taker;
function take(cb) {
taker = cb;
}
function put(input) {
if(taker){
const tempTaker = taker;
taker = null;
tempTaker(input);
}
}
return{
put,
take,
};
}
const chan = channel();
let i = 0;
$btn.addEventListener('click', () => {
chan.put(`action data${i++}`);
}, false);
function take() {
return {
type: 'take'
};
}
function fork(cb) {
return {
type: 'fork',
fn: cb,
};
}
function* takeEvery(worker) {
// worker 就是传进来的函数
yield fork(/*标注*/function* () {
while(true) {
const action = yield take();
worker(action);
}
});
}
function* mainSaga() {
yield takeEvery(action => {
$result.innerHTML = action;
});
}
function runTakeEffect(cb){
//调用chan.take 添加一个监听 put action 的时候执行next(input) 这个时候执行work action 去改变$result的内容
//再次点击 Clickme 按钮的时候因为task 中的 iterator 还是 上面的标注函数 因为里面部署了while 循环 所以就会源源不断的相应 put 进来的action 执行worker
chan.take(input => {
cb(input);
});
}
//fork的作用是启动一个新的task,不阻塞原task执行
function runForkEffect(effect, cb) {
//3,runForkEffect 中调用task 把takeEvery 传进来
//6.effect 为上面标注的函数的时候 在次调用task
task(effect.fn || effect);
cb();
}
function task(iterator) {
console.log(iterator)
const iter = typeof iterator === 'function' ? iterator() : iterator;
function next(args) {
const result = iter.next(args);
console.log(result);
if (!result.done) {
const data = result.value;
// 1,iterator 为mainSaga 时候 ->判断data 的值是否为generator 函数 takeEvery 满足此项
//4,iterator 为takeEvery 时候 data的 值为{type: "fork", fn: ƒ} fn的值就是fork 中传进来的函数 见 上面标注部分 此时走下面switch 部分逻辑
//7,iterator 为 标注函数的时候 data的值为 {type: 'take'};
if (typeof data[Symbol.iterator] === 'function') {
//2,,iterator 为mainSaga 时候 ->然后执行 把 takeEvery 和next 传给 runForkEffect
runForkEffect(data, next);
} else if (data.type) {
switch (data.type) {
case 'take':
//8 把next; 传给runTakeEffect
runTakeEffect(next);
break;
case 'fork':
//5,把{type: "fork", fn: ƒ} 传给runForkEffect
runForkEffect(data, next);
break;
default:
}
}
}
}
next();
}
//1执行前 调用task部署任务 task 本质上是一个 Thunk函数对generator函数的自动流程管理
task(mainSaga);
</script>
</body>
</html>
takeLatest 和 takeEvery 的区别是 :
takeEvery
允许多个 任务
实例同时启动,尽管之前还有一个或多个 任务
尚未结束
takeLatest
只允许一个任务在执行。并且这个任务是最后被启动的那个。 如果已经有一个任务在执行的时候启动另一个 任
务 ,那之前的这个任务会被自动取消。
简单做个图解