当前位置: 代码迷 >> 综合 >> 从 generator 函数 到 redux -saga (四)
  详细解决方案

从 generator 函数 到 redux -saga (四)

热度:84   发布时间:2023-11-21 05:20:13.0

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 执行workerchan.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 传给 runForkEffectrunForkEffect(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 只允许一个任务在执行。并且这个任务是最后被启动的那个。 如果已经有一个任务在执行的时候启动另一个

   务 ,那之前的这个任务会被自动取消。

简单做个图解 

图解

 

  相关解决方案