今天群里有朋友问了一个问题,saga为什么不能用asyncawait实现?想必开始接触redux-saga的同学都有这样的疑问,为什么呢?可以使用异步等待而不是生成器吗?import{put,call}from'redux-saga/effects'import{loginService}from'../service/request'function*login(action){try{constloginInfo=yieldcall(loginService,action.account)yieldput({type:'loginSuccess',loginInfo})}catch(error){yieldput({type:'loginFail',error})}}刚开始用saga的时候想问这个问题,但是理解了saga的原理之后,我以为明白了。让我们在下面探讨它。saga的原理是我们把action从component发送到store,这个过程是同步的。但是哪里添加了一些异步进程呢?中间件。Reduxsaga首先会透明的把action传递给store,这个过程是同步的。然后传一份给watchersaga,看看是不是被监控的动作。如果交给workersaga处理,workersaga可以在处理过程中向store放一个新的action。这个过程是异步的。这就是redux-saga的原理,原理上比较简单。亮点在于异步过程的组织,即生成器。为什么使用generator来组织异步流程是redux-saga的亮点?别着急,我们先来了解一下什么是生成器。生成器生成器(generator)是一个生成迭代器(iterator)的函数,通过yield一个一个的返回值。迭代器是具有value和done属性的对象,用于顺序遍历集合。我们可以调用iterator.next来获取yield生成的值。也可以使用Array.from或者展开运算符获取,这是iterator的特性。除了next方法,迭代器还有return和throw方法,就像函数中的return和throw语句一样。比如用iterator.return终止后续流程,用iterator.throw抛出错误,意思是generator的执行由一个executor控制,什么时候removeayield的值,什么时候next,什么时候返回和何时抛出由执行者控制。执行器可以将next、return、throw参数传给生成器执行结果:上面的代码是一个小saga,原理就这么简单。那为什么不异步等待工作?当asyncawait返回generator的值为Promise时,那么Promise执行后,只有resolve和reject两种结果。这个executor是很固定的,自然可以写一个通用的executor来调用next,throw,return。这就是asyncawait的原理,只不过被做成了语法糖。asyncawait本质上只不过是一个生成器执行器。如果redux-saga是用asyncawait实现的,那么所有的异步逻辑都必须命令式的写在awa??it后面,这样会导致异步过程难以测试。所以redux-saga自己实现了一个executor。再看看这个saga代码:.account)yieldput({type:'loginSuccess',loginInfo})}catch(error){yieldput({type:'loginFail',error})}}generator中的yield不是一个promise,而是一个effect,这个实际上是一个对象,它以声明方式告诉saga执行器要做什么,而不是命令式地执行它。这样generator的executor根据不同的effect实现不同:calleffect有对应的实现,puteffect也有对应的实现,也就是说saga的generatorexecutor不会做asyncawait之类的事情,但有你自己的运行时在那里。这样做有什么好处?可以代替sagaeffect的具体执行逻辑,方便测试。例如,如果你从请求数据切换到直接返回值,你甚至不需要模拟。可以内置一系列saga来方便组织异步流程,比如throttle、debounce、race等。现在,让我们回到最初的问题,redux-saga可以用asyncawait来实现吗?可以,但是asyncawait是一个generator的自动执行,没有runtime逻辑,异步过程必须命令式写在saga中。如果自己实现一个generatorexecutor,可以将异步过程抽取出来,方便组织和测试。如果你用asyncawait来实现saga,你就会失去灵魂。总结一下,redux-saga的原理就是透传action给store,然后再给saga组织的异步进程传一个aciton。saga分为watchersaga和workersaga。watchersaga判断action是否需要处理,然后交给workersaga处理。生成器generator是一个返回iterator迭代器的函数。迭代器有next、throw、return等方法,需要用executor来执行。asyncawait本质上是一个生成器的自动执行器。如果使用asyncawait实现reduxsaga,需要命令式组织异步过程,测试难度大。所以redux-saga实现了一个带有自己运行时的生成器执行器。生成器只需要返回effect对象声明性的描述执行什么逻辑,然后相应的effect实现就会去执行。这种声明式的思想不仅易于组织异步过程,而且具有很好的可测试性。generator+sagaexecutor的设计是redux-saga的灵魂,所以不能用asyncawait来实现。
