从 generator 函数 到 redux -saga (四)

版权声明:如需转载请著明出处 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 只允许一个任务在执行。并且这个任务是最后被启动的那个。 如果已经有一个任务在执行的时候启动另一个

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

简单做个图解 

图解

猜你喜欢

转载自blog.csdn.net/qq_37653449/article/details/85563013
今日推荐