接着来说,generator生成器函数:看似同步的异步流程控制风格。
基础部分可以看一下阮一峰老师的 生成器函数的概念了解一下。
这里只做一些 生成器函数配合promise的高级使用。
在生成器函数中可以 同步的使用try catch来捕获错误。
生成器中可以使用yield 来等待 异步promise的返回,这样我们配合使用就可以 同步的来监听 异步任务里的错误。
支持Promsie的Generator Runner
如何自动从执行到结束一个生成器函数,asynquence 这个库里的runner()做了实现,现在我们来实现一个自己简易版本,run(...)
function run(gen){
var args = [].slice.call(arguments,1);//不包含第一个之后的参数
var it = gen.apply(this,args);//用当前上下文 还有args参数初始化生成器
return Prommise.resolve().then(function handleNext(value){
var next = it.next(value);//对下一个yield出的值运行
return (function handleResult(next){
if(next.done){//如果迭代到最后,生成器函数运行完毕
return next.value;
}else{//未运行完毕
//next.value的值不一定是promsie,有可能是个立即值,所以通过promise.resolve()统一转成异步操作
return Promise.resolve(next.value).then(
handleNext,//成功就回复异步循环,把决议的值发回生成器
function handleErr(err){
//如果value是 被拒绝的promise,就把错误传回生成器进行出错处理
//[https://www.axihe.com/api/js-es/ob-generator/throw.html](https://www.axihe.com/api/js-es/ob-generator/throw.html)
//it.throw(err)类似it.next 也会继续往下走,处理错误,返回 next对象包含done和value
return Promise.resolve(it.throw(err)).then(handleResult)
}
)
}
})(next)
})
}
//测试调用
function foo(b) {
return request(b);
}
function request(b) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
if (b) {
resolve('100')
} else {
reject('200')
}
}, 2000)
})
}
function *main() {
try {
var texts = yield foo();
console.log(texts)
var text = yield foo(true);
console.log(text)
} catch (err) {
console.error(err);
}
var text = yield foo(true);
console.log(text)
return 40;
}
console.log(run(main).then(function (v) { console.log(v) }))
这种自动运行run的方式,它会自动异步运行你传给它的生成器。
这种模式看起来是不是很眼熟,这就是async与await的前身
ES7的 async和await如下
function foo(x,y){
return request('http://...')
}
async function main(){
try{
var text = await foo(1,51);
console.log(text)
}catch(err){
console.error(err)
}
}
main()
使用async关键词修饰。
生成器中promise的并发。
使用生成器实现异步的方法全部要点在于创建简单,顺序,看似同步的代码,将异步的细节尽可能的隐藏起来。
function bar(url1,url2){
return Promise.all([
request(url1),
request(url2)
])
}
function *foo(){
var results = yield bar('http://...1','http://...2');
const [r1,r2] = results;
var r3 = request('http://...3'+r1+r2)
console.log(r3)
}
//更高级的用法,组合promise 的api
function bar(){
Promise.all([baz(...).then(...),Promise.race([...])]).then(...)
}
像bar方法里这种逻辑,如果直接放在生成器内部的话,那就失去了一开始使用生成器的理由,应该有意把这样的细节从生成器中抽象出来,以避免它把高层次的任务表达变得杂乱。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。