[前端怪谈_2]从 Dva 的 Effect 到 Generator + Promise 实现异步编程
栏目: JavaScript · 发布时间: 5年前
内容简介:结合上一篇文章 ,我们来聊聊dva 中有一个开始之前,我们需要了解一些基本的概念:
结合上一篇文章 ,我们来聊聊 Generator
基础原理
dva 中有一个 Effect
的概念,它就是使用 Generator
来解决异步请求的问题,我们也来聊一聊 Generator
+ Promise
如何异步编程:
开始之前,我们需要了解一些基本的概念:
-
Generator
作为ES6中使用协程的解决方案来处理异步编程的具体实现,它的特点是:Generator
中可以使用yield
关键字配合实例gen
调用next()
方法,来将其内部的语句分割执行。 简言之 :next()
被调用一次,则yield
语句被执行一句,随着next()
调用,yield
语句被依次执行。 -
Promise
表示一个异步操作的最终状态(完成或失败),以及其返回的值。参考Promise-MDN
所以,异步编程使用 Generator
和 Promise
来实现的原理是什么呢?
- 因为
Generator
本身yield
语句是分离执行的,所以我们利用这一点,在yield
语句中返回一个Promise
对象 - 首次调用
Generator
中的next()
后, 假设返回值叫result
,那么此时result.value
就是我们定义在yield
语句中的Promise
对象
注意:在这一步,我们已经把原来的执行流程暂停,转而执行 Promise
的内容,已经实现了控制异步代码的执行,因为此时我们如果不继续执行 next()
则 generator
中位于当前被执行的 yield
后面的内容,将不会继续执行,这已经达到了我们需要的效果 3. 接下来我们就是在执行完当前 Promise
之后,让代码继续往下执行,直到遇到下一个 yield
语句:
这一步是最关键的 所以我们怎么做呢:
步骤1: 在当前的 Promise
的 then()
方法中,继续执行 gen.next()
步骤2: 当 gen.next()
返回的结果 result.done === true
时,我们拿到 result.value
【也就是一个新的 Promise
对象】再次执行并且在它的 then()
方法中继续上面的步骤1,直至 result.done === false
的时候。这时候调用 resolve()
使 promise
状态改变,因为所有的 yield
语句已经被执行完。
- 步骤1 保证了我们可以走到下一个
yield
语句 - 步骤2 保证了下一个
yield
语句执行完不会中断,直至Generator
中的最后一个yield
语句被执行完。 流程示意图:
具体实现
从 co
库中的一个demo开始,了解我们的整个异步请求封装实现
co(function*() { yield me.loginAction(me.form); ... }); 复制代码
在这里我们引入了 co
库,并且用 co
来包裹了一个 generator
(生成器)对象。
接下来我们看下 co
对于包裹起来的 generator
做了什么处理
function co(gen) { // 1.获取当前co函数的执行上下文环境,获取到参数列表 var ctx = this; var args = slice.call(arguments, 1); // 2.返回一个Promise对象 return new Promise(function(resolve, reject) { // 判断并且使用ctx:context(上下文环境)和arg:arguments(参数列表)初始化generator并且复制给gen // 注意: // gen = gen.apply(ctx, args)之后 // 我们调用 gen.next() 时,返回的是一个指针,实际的值是一个对象 // 对象的形式:{done:[false | true], value: ''} if (typeof gen === 'function') gen = gen.apply(ctx, args); // 当返回值不为gen时或者gen.next的类型不为function【实际是判断是否为generator】时 // 当前promise状态被设置为resolve而结束 if (!gen || typeof gen.next !== 'function') return resolve(gen); // 否则执行onFulfilled() onFulfilled(); }); } 复制代码
总结一下这里发生了什么
- 返回一个
promise
-
promise
中将被包裹的generator
实例化为一个指针,指向generator
中第一个yield
语句 - 判断
generator
实例化出来的指针是否存在:如果没有yield
语句则指针不存在 判断指针gen.next()
方法是否为function
:如果不为function
证明无法执行gen.next()
条件有一项不满足就将promise
的状态置为resolve
否则执行onFulfilled()
接下来我们看下 onFulfilled()
的实现
function onFulfilled(res) { // 在执行onFulfilled时,定义了一个ret来储存gen.next(res)执行后的指针对象 var ret; try { ret = gen.next(res); // 在这里,yield语句抛出的值就是{value:me.loginAction(me.form), done:false} } catch (e) { return reject(e); } // 将ret对象传入到我们定义在promise中的next方法中 next(ret); return null; } 复制代码
总结一下, onFulfilled
最主要的工作就是
- 执行
gen.next()
使代码执行到yield
语句 - 将执行后返回的结果传入我们自定义的
next()
方法中
那么我们再来看 next()
方法
function next(ret) { // 进入next中首先判断我们传入的ret的done状态: // 情况1:ret.done = true 代表我们这个generator中所有yield语句都已经执行完。 // 那么将ret.value传入到resolve()中,promise的状态变成解决,整个过程结束。 if (ret.done) return resolve(ret.value); // 情况2:当前ret.done = false 代表generator还未将所有的yield语句执行完,那么这时候 // 我们把当前上下文和ret.value传入toPromise中,将其转换为对应的Promise对象`value` var value = toPromise.call(ctx, ret.value); if (value && isPromise(value)) return value.then(onFulfilled, onRejected); // 当value确实是一个promise对象的时候,return value.then(onFulfilled,onRejected) // 我们重新进入到了generator中,执行下一条yield语句 return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, ' + 'but the following object was passed: "' + String(ret.value) + '"')); } 复制代码
总结一下, next
主要工作
- 判断上一次
yield
语句的执行结果 - 将
yield
的result
的value
值【其实就是我们要异步执行的Promise
】 - 执行
value
的then
方法,重新进入到onFulfilled
方法中,而在onFulfilled
中,我们又将进入到当前方法,如此循环的调用,实现了generator
和Promise
的执行切换,从而实现了Promise
的内容按照我们所定义的顺序执行。
至此实现异步操作的控制。
以上所述就是小编给大家介绍的《[前端怪谈_2]从 Dva 的 Effect 到 Generator + Promise 实现异步编程》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- [前端怪谈_1] 从 for of 聊到 Generator
- SpringBoot | :异步开发之异步调用
- 改进异步封装:处理带返回值的异步调用
- 异步发展流程 —— Generators + co 让异步更优雅
- 文件系统与异步操作——异步IO那些破事
- js异步从入门到放弃(四)- Generator 封装异步任务
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Java Script深度剖析
卢云鹏、沈维伦、Don Gosselin、李筱青 / 卢云鹏、沈维伦、李筱青 / 北京大学出版社 / 2004-10-1 / 49.0
本书适合于大中专院计算机相关专业作为教材,也是JavaScript初学者以及JavaScript爱好者的理想参考用书。书中详细介绍了基本的JavaScript程序设计原理以及实现它们的语法,内容包括JavaScript简介,变理、函数、对角和事件,数据类型、运算符,结构化逻辑控制结构和语句,窗口和框架,表单,动态HTML和动画,cookie和安全性,服务器端 JavaScript,数据库连接,使用......一起来看看 《Java Script深度剖析》 这本书的介绍吧!