头几天研讨了TJ的koa/co4.x和一系列koa依靠的源码,在知乎上做出了人生初次回复(而且我真得不再想去知乎回复技术问题了_(:з」∠)_),因而把笔墨搬到这里。
ES2015 Generator/Yield
关于Generator/Yield 这几篇文章已写得充足清楚了:
- The Basics Of ES6 Generators
- Diving Deeper With ES6 Generators
- Going Async With ES6 Generators
- Getting Concurrent With ES6 Generators
Koa的运行机制
简朴地画了一张图诠释koa的处置惩罚流程:
在koa里定义的middleware均为generator function(包含内置在顶端的respond),这是为了能从恣意middleware中容易地切换到别的middleware里(假如你是前端程序员,能够理解为浏览器捕捉事宜的capture和propagation历程,假如你是python程序员,能够理解为jungle的middleware机制,假如你是Java程序员,这类体式格局则是典范的切面编程)。
为了完成这类横穿多个middleware的特征,koa经由过程把后一个generator作为参数(koa里经常使用next)传入前一个generator完成(#见koa-compose源码,这也是为何前两个middleware有next参数而末了一个没有)。
能够看到,在koa中yield的使用是在co,而co则是包装了generator/yield & Promise以模仿async/await,供应了一个更高条理的异步语法笼统。
koa在加载且兼并一切的middleware以后,传递给co实行(确实地说是在http.createServer的callback触发后实行),co以图中所示逻辑不停拆解generator function,实行yield右边牢固的几种表达式(Array,Object,generator function,Promise,thunkify function),这5种表达式终究都邑转化为Promise,以到达处置惩罚异步函数的目标。
co内部封装了onFulfilled和onRejected函数,当yield右边的promise resolve以后,则会挪用onFullfield函数,其包含了一条症结语句gen.next(res)#这句代码 用以给yield表达式赋值并实行下一次迭代。
koa经由过程上文的体式格局「深切」->「浅出」,终究在顶层的respond middleware里send response。
注:#thunk是co先前版本处置惩罚异步函数的体式格局,经由过程thunk能够将异步函数封装成curry,传入一般参数后构成仅须要callback参数的偏函数,以此简化callback挪用代码(现在co中的thunk偏函数已被#无情地Promise化了)。