从C#到TypeScript - Generator
从C#到TypeScript - Generator
上篇讲了Promise
,Promise
的执行需要不停的调用then
,虽然比callback要好些,但也显得累赘。所以ES6里添加了Generator
来做流程控制,可以更直观的执行Promise,但终级方案还是ES7议案中的async await
。
当然async await
本质上也还是Generator
,可以算是Generator
的语法糖。
所以这篇先来看下Generator.
Generator语法
先来看个例子:
function* getAsync(id: string){ yield 'id'; yield id; return 'finish'; } let p = getAsync('123'); console.info(p.next()); console.info(p.next()); console.info(p.next());
先看下和普通函数的区别,function
后面多了一个*
,变成了function*
,函数体用到了yield
,这个大家比较熟悉,C#也有,返回可枚举集合有时会用到。
在ES6里yield
同样表示返回一个迭代器,所以用到的时候会用next()
来顺序执行返回的迭代器函数。
上面代码返回的结果如下:
{ value: 'id', done: false } { value: '123', done: false } { value: 'finish', done: true }
可以看到next()
的结果是一个对象,value
表示yield
的结果,done
表示是否真正执行完。
所以看到最后return了finish
时done
就变成true了,如果这时再继续执行next()
得到的结果是{ value: undefined, done: true }
.
Generator原理和使用
Generator
其实是ES6对协程的一种实现,即在函数执行过程中允许保存上下文同时暂停执行当前函数转而去执行其他代码,过段时间后达到条件时继续以上下文执行函数后面内容。
所谓协程其实可以看做是比线程更小的执行单位,一个线程可以有多个协程,协程也会有自己的调用栈,不过一个线程里同一时间只能有一个协程在执行。
而且线程是资源抢占式的,而协程则是合作式的,怎样执行是由协程自己决定。
由于JavaScript是单线程语言,本身就是一个不停循环的执行器,所以它的协程是比较简单的,线程和协程关系是 1:N。
同样是基于协程goroutine的go语言实现的是 M:N,要同时协调多个线程和协程,复杂得多。
在Generator
中碰到yield
时会暂停执行后面代码,碰到有next()
时再继续执行下面部分。
当函数符合Generator
语法时,直接执行时返回的不是一个确切的结果,而是一个函数迭代器,因此也可以用for...of
来遍历,遍历时碰到结果done
为true则停止。
function* getAsync(id: string){ yield 'id'; yield id; return 'finish'; } let p = getAsync('123'); for(let id of p){ console.info(id); }
打印的结果是:
id
123
因为最后一个finish
的done
是true,所以for...of
停止遍历,最后一个就不会打印出来。
另外,Generator
的next()
是可以带参数的,
function* calc(num: number){ let count = yield 1 + num; return count + 1; } let p = calc(2); console.info(p.next().value); // 3 console.info(p.next().value); // NaN //console.info(p.next(3).value); // 4
上面的代码第一个输出是yield 1 + num
的结果,yield 1
返回1,加上传进来的2,结果是3.
继续输出第二个,按正常想法,应该输出3,但是由于yield 1
是上一轮计算的,这轮碰到上一轮的yield
时返回的总是undefined
。
这就导致yield 1
返回undefined
,undefined + num返回的是NaN
,count + 1也还是NaN,所以输出是NaN
。
注释掉第二个,使用第三个就可以返回预期的值,第三个把上一次的结果3用next(3)传进去,所以可以得到正确结果。
如果想一次调用所有,可以用这次方式来递归调用:
let curr = p.next();
while(!curr.done){console.info(curr.value);curr = p.next(curr.value);
}
console.info(curr.value); // 最终结果
Generator
可以配合Promise
来更直观的完成异步操作。
function delay(): Promise<void>{ return new Promise<void>((resolve, reject)=>{setTimeout(()=>resolve(), 2000)}); } function* run(){ console.info('start'); yield delay(); console.info('finish'); } let generator = run(); generator.next().value.then(()=>generator.next());
就run
这个函数来看,从上到下执行是很好理解的,先输出'start',等待2秒,再输出'finish'。
只是执行时需要不停的使用then
,好在TJ大神写了CO模块,可以方便的执行这种函数,把Generator
函数传给co
即可。
co(run).then(()=>console.info('success'));
co的实现原理可以看下它的核心代码:
function co(gen) { var ctx = this; var args = slice.call(arguments, 1); return new Promise(function(resolve, reject) { if (typeof gen === 'function') gen = gen.apply(ctx, args); if (!gen || typeof gen.next !== 'function') return resolve(gen); onFulfilled(); //最主要就是这个函数,递归执行next()和then() function onFulfilled(res) { var ret; try { ret = gen.next(res); // next(), res是上一轮的结果 } catch (e) { return reject(e); } next(ret); // 里面调用then,并再次调用onFulfilled()实现递归 return null; } function onRejected(err) { // 处理失败的情况 var ret; try { ret = gen.throw(err); } catch (e) { return reject(e); } next(ret); } function next(ret) { if (ret.done) return resolve(ret.value); // done是true的话表示完成,结束递归 var value = toPromise.call(ctx, ret.value); if (value && isPromise(value)) return value.then(onFulfilled, onRejected); //递归onFulfilled return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, ' + 'but the following object was passed: "' + String(ret.value) + '"')); } }); }
可以看到co的核心代码和我上面写的递归调用Generator
函数的本质是一样的,不断调用下一个Promise,直到done
为true。
纵使有co这个库,但是使用起来还是略有不爽,下篇就轮到async await
出场,前面这两篇都是为了更好的理解下一篇。
转载于:https://www.cnblogs.com/yulei126/p/6790030.html
从C#到TypeScript - Generator相关推荐
- 【 malcolmcrum】基于Java后端与Typescript前端的代码自动生成
Java 后端和 Typescript 前端虽然都是类型语言,但传统上这两个域上的类型之间存在脱节.本文推荐的这个工具让我们在一个地方修改一个方法或类,并立即在其他地方直接使用它,或者在我们误用它时在 ...
- TypeScript 学习一 参数,函数,析构表达式
1,TypeScript是由微软开发的,不过新出的Angular2框架就是谷歌公司由TypeScript语言编写的,所以现在TypeScript是有微软和谷歌一起支持的: 2,TypeScript在j ...
- typescript 使用_如何使用TypeScript轻松修改Minecraft
typescript 使用 by Josh Wulf 通过乔什·沃尔夫(Josh Wulf) 如何使用TypeScript轻松修改Minecraft (How to modify Minecraft ...
- 自动化yaml文件_从YAML到TypeScript:开发人员对云自动化的看法
自动化yaml文件 The rise of managed cloud services, cloud-native, and serverless applications brings both ...
- typescript在ES3(IE7)环境下使用async、await
因为公司产品需要搞个Web App,但是又需要兼容IE7,这时候整个应用会非常复杂,尤其是在处理异步的时候,在我的选择中有两个方案 callback方案 async/await 经过衡量以后,决定使用 ...
- TypeScript入门教程 之 生成器函数
TypeScript入门教程 之 生成器函数 生成器函数 function *是用于创建生成器函数的语法.调用generator函数将返回一个generator对象.发电机对象如下刚刚所述迭代器接口( ...
- TypeScript 令我苦不堪言
作者 | Ilya Suzdalnitski 责编 | 弯月 出品 | CSDN(ID:CSDNnews) 你是否被 TypeScript 的炒作假象所欺骗?TypeScript 真比 JavaScr ...
- 方法 手写promise_实现一个符合 Promise/A+规范的 Promise(typescript 版)
(给前端大全加星标,提升前端技能) 转自:Col0ring juejin.cn/post/6886360224308035598 写在前面 没错,这又是一篇关于手写 Promise 的文章,想必大家已 ...
- TypeScript + ES6
TypeScript = 微软开发+Js超集+遵循ES6 优势 (1)支持ES6规范 (2)强大的IDE支持 (3)Angular2的开发语言 搭建TS开发环境 (1)在线环境 http://www. ...
最新文章
- QEMU-KVM自己主动创建虚拟机,以指定IP构造
- latex 引用_VS Code + LaTex + Zotero 写作毕业论文
- linux启动顺序怎么修改,怎样修改启动顺序?
- Linux(CentOS)挂载NTFS格式的U盘、移动硬盘
- springCloud 微服务框架搭建入门
- python代码块缩进_Python代码需要缩进吗
- Redis集群之哨兵模式
- 毕设题目:Matlab元胞自动机交通流
- 2018地图poi数据下载
- jdbcTemplate批量插入数据
- Oracle技巧查询,很香
- H3C交换机端口链路聚合
- WordPress教程网站
- 【7gyy】解决Win8没声音,无法联网,分辨率问题的方法
- 【华人学者风采】徐泽水 四川大学
- Android心电数据分析,Android 根据心电图(ECG)数据分析绘制心电图
- iOS刻度尺换算之1mm等于多少像素理解
- MPU6500的使用之代码展示
- 动态生成验证码+验证码的校验
- 天朝挖煤的题已经不会做了。。