《姜天意利用yield与koa解决nodejs异步回调嵌套问题.ppt》由会员分享,可在线阅读,更多相关《姜天意利用yield与koa解决nodejs异步回调嵌套问题.ppt(35页珍藏版)》请在三一办公上搜索。
1、1,Todo,异步回调问题解决方案Yield与generator实现一个流程控制器-koa的核心Koa。,2,开始的问题,某天,你邂逅了一个美女。他给你提了个要求。请200毫秒后亲我一下,再等3000毫秒后亲我一下,再等1000毫秒后亲我一下。,3,如何解决?,以下是宇宙号js引擎核心设计代码最后一页,4,从一个函数看起,var copy=function(src,dst)var fd_src=fs.open(src,“r”);var fd_dst=fs.open(dst,“w”);while(true)var bytes_read=fs.read(fd_src,buffer,0,buffer
2、_size);fs.write(fd_dst,buffer,bytes_read);但这是实现不了的,5,6,解决方案1 eventproxy,var ep=EventProxy.create(“template”,“data”,function(template,data)_.template(template,data););$.get(template,function(template)/something ep.emit(template,template););$.get(data,function(data)/something ep.emit(data,data););/源码分
3、析http:/,7,解决方案2 Promises/A,http:/,缺点:重,8,解决方案3 asynceach,var arr=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20var asyncEach=function(fn,arr)var l=arr.length,i=-1;var run=function()i+=1;if(i=l)return;fn(arri,run);/需要fn第二个参数为callback,callback必须要传到run里面;run();https:/,缺点:没有流程跟逻辑性,9,还有很多的解决方案。,但你考虑过
4、这种写法么?exports.updateById=function*(id,task)yield db.open(config);var row=yield db.get(id);/异步操作for(var key in task)rowkey=taskkey;yield db.put(id,row);/异步操作;,10,yield&generator,ES6 中的生成器函数(generator function),目前浏览器中只有 Chrome 29+支持它,不过还是先要在 about:flags 中启用实验性JavaScript(Enable Experimental JavaScript)
5、function*foo1();function*foo2();function*foo3();foo1.toString();/function*foo1()foo2.toString();/function*foo2()foo3.toString();/function*foo3()foo1.constructor;/function GeneratorFunction()native code 注意,函数并不执行!,11,yield&generator,调用生成器函数会产生一个生成器(generator)。生成器拥有的最重要的方法是 next(),用来迭代:function*foo();
6、varbar=foo();/注意,函数并不执行!bar.next();/Object value:undefined,done:true,12,举个栗子,生成器函数通常和 yield 关键字同时使用。函数执行到每个 yield 时都会中断并返回 yield 的右值(通过 next 方法返回对象中的 value 字段)。下次调用 next,函数会从 yield 的下一个语句继续执行。等到整个函数执行完,next 方法返回的 done 字段会变成 true。function*test()yield 1;yield 2;yield 3;yield 4;console.log(11111);,valu
7、e:1,done:false,13,这尼玛啥用啊?,14,举个栗子,整体控制流程,返回一个生成器,这个生成器可以自己去不断的调用next()方法,从而控制内部函数的执行。我们用整体 runOneByOne函数来控制整个流程。,15,How to?,16,这个函数有什么问题?,并未真正关注整体与个体的关系,17,这个函数有什么问题?,虽然我们可以用整体控制流程,代替了javascript自己去执行的过程。但是,个体的执行结果,仍然对整体是不可见的。解决方法:整体提供执行方法(“下一步-nextStep”),个体,提供执行反馈,在个体执行完毕后,个体的反馈(callback)中,去运行整体的“下一
8、步”执行方法。还记得value方法吗?Value返回yield的右值,因此只需要把右值变成一个可以接收反馈的函数即可。,18,第一步,改造亲嘴函数,亲嘴函数作为yield右边,执行后可以返回一个函数,这个函数接收一个callback。,19,第二步,修改nextStep的调用,20,补充:错误处理(来自小乔),通常的错误捕获需要把异步函数的错误一层层向上传递。yield只需要捕获某一步next的错误即可,21,我们到底实现了什么?,通过整体控制流程,个体只需要改造一下,返回一个函数即可。书写方式变化,不再需要关注无穷无尽的回调。runOneByOne-co koa 框架的核心。,runOneB
9、yOne(function*()yield 亲嘴(200)yield 亲嘴(3000)yield 亲嘴(1000)(),22,yieldable and thunk需要将所有的 callback 都转换成 thunk:function(args)return function 亲嘴(done)fn(args,done);,23,callback to thunkThunkifythunkify-wrapfs.stat(filename,callback);/=function stat(filename)return function(done)fs.stat(filename,done);/
10、=function*()yield stat(./README.md);,24,基于 generator 的异步编程var thunkify=require(thunkify);var co=require(co);/刚才我们实现的runOneByOnevar fs=require(fs);var stat=thunkify(fs.stat);var readFile=thunkify(fs.readFile);co(function*()var stat=yield stat(./README.md);var content=yield readFile(./README.md);)();,
11、25,Co需要什么?,可以被 yield 的有:thunk,promise,generator,generatorFunction,object,array所有的 node 形式的 callback 都需要转换成thunkobject,array,promise自动识别并转换成thunkgenerator,generatorFunction自动识别并展开执行,26,KoaTJ 和 express 团队的新作品基于 generator 和 co 的异步解决方案setter/getter 带来了更方便的 http 辅助方法更人性化的错误处理更灵活的中间件形式,27,koa VS express不提
12、供默认路由不提供默认的模版渲染不支持 node 原生的 request 和 response不支持 express 中间件提供默认的异步解决方案(generator)更有表现力的中间件形式对 request/response 提供更好体验的中间件,28,中间件技术是什么,29,Express的中间件,varhttp=require(http);varconnect=require(connect);varapp=connect();app.use(function(req,res)res.end(Hello!););http.createServer(app).listen(3000);更厚一
13、层的洋葱皮,30,koa的中间件,var koa=require(koa);var ejs=require(koa-ejs);var app=koa();ejs(app,/*options*/);/挂载 function*render()在 context.prototype上 app.use(function*()return yield this.render(index););作为一个洋葱皮上的工具,31,koa的中间件,var koa=require(koa);var session=require(koa-sess);var app=koa();app.use(session(def
14、er:true);/挂载 session(getter 作为一个洋葱皮上的属性,32,koa的异步 舒爽。,var fs=require(co-fs);app.use(function*()var paths=yield fs.readdir(docs);/parallel var files=yield paths.map(function(path)return fs.readFile(docs/+path,utf8););this.type=markdown;this.body=files.join(););,33,More,https:/,https:/,https:/,34,我们需要解决什么问题?,流程控制非常困难-whenjs,async,异步回调嵌套过多,写法很恶心-windjs,koa/generator,错误处理 event/promise/domain,35,Q&A,