#开始使用Koa,第二部分(译)
http://blog.risingstack.com/getting-started-with-koa-part-2/
原作者: Gellért Hegyi https://twitter.com/native_cat
在上一节我们掌握了generators并且明白了一点,那就是我们可以以同步的形式编写代码而异步的执行。这非常棒,因为同步代码非常简单,优雅而且具有更好的可读性,而异步代码可能会导致“尖叫”与“哭泣”(回调地狱)。
这一章将讲述解决这个痛苦的工具,这样我们就可以只编写那些有趣的部分。它会给予基本Koa特性和机制的介绍。
前述
1 | // First part |
在上一篇文章的最后一个例子里,如你所见,我们可以将其分为3个重要地部分。第一是我们必须创造我们的thunkified functions,它会被用在一个generator中。然后我们必须使用thunkified functions编写我们的generator functions。最后一个部分是我们调用并遍历generators,处理异常以及其他。如果你想一想你会发现,最有一部分和我们程序的本质并没有什么关系,基本上它让我们运行一个generator。幸运地是,有一个模块帮我们这样做。来见一见co。
CO
Co是一个node的基于generator的流程控制模块。下面的代码和上面做的事情完全一样,但是我们摆脱了调用generator的代码。唯一我们需要做的事情,是将generator传递给一个函数co
,调用它,然后魔力就发生了。好吧,其实并不是什么魔力,它只是为你处理所有的generator调用代码,因此我们不需要为那操心了。
1 | var co = require('co'); |
就像我们已经知道的那样,你可以防止一个yield
z在任何东西之前来对一些东西进行评价。因此并不是只有trunks可以被yield
。因为co
想要创建一个简单的控制流,它对一些特殊的类型进行yield。当前支持yield的类型:
- thunks(函数)
- array (并发执行)
- objects (并发执行)
- generators (代理)
- generator functions (代理)
- promises
我们已经讨论过thunks是如何工作的了,因此让我们去看看其他的。
并发执行
1 | var read = thunkify(fs.readFile); |
如果你yield
一个数组或一个对象,它将并行地评估它的内容。当然你的集合也可以是thunks
、generators
。你可以nest,它会穿过数组或者对象并发执行你所有的函数。注意:被yield的结果不会是展开的,它会保留同样的结构。
1 | var read = thunkify(fs.readFile); |
你也可以通过在thunk的调用之后进行yield实现并发。
1 | var read = thunkify(fs.readFile); |
代理
你当然也可以yield generators。注意我们并不需要使用yield *
。
1 | var stat = thunkify(fs.stat); |
我们过一下产不多所有你使用co
时进行yield的可能性。这里有一个最新的示例(取自于co的github页面)把它们结合起来。
1 | var co = require('co'); |
我相信现在你已经足够掌握generators了,你已有有了一个关于如何使用这些工具操作异步控制流的很好的概念。
现在是时候转到我们整个系列的主题,Koa了!
Koa
你所需要知道的,关于koa
模块自身的信息并没有多少。你甚至可以看它的源码,只有4个文件,每个文件约300行。Koa遵循你写的每个程序都只做并且做好一件事情的传统。因此你会看到,每个好的koa模块都是(并且每个node模块都应该是)简短的。只做一件事情并且重度依赖于其他模块。你应该记住这些并且依照它进行开发。它会有利于每个人,你以及其他阅读你源代码的人。记住这一点然后让我们移动到Koa的主要特性。
应用
1 | var koa = require('koa'); |
创建一个Koa应用只是简单的引入模块函数。这提供给你一个对象,它包含了一个generators(中间件)的数组,对一个新的请求以类似栈的方式进行执行。
级联
一个重要的术语,当使用Koa时,它指的是中间件。因此让我们先弄清楚这个。
Koa中的中间件是处理请求的函数。一个由Koa创建的服务器可以有一个与它关联的中间件的栈。
Koa中的级联的意思是,控制流穿过一系列的中间件。在Web开发中这是非常重要的,你可以简单地用这种方式构造复杂的行为。Koa使用generator非常直观并且简洁地实现它。它yield下游,然后控制流程回到上游。要向流程中添加一个generator,调用use
函数并传入一个generator。试着猜猜看为什么下面的代码对每一个到达的请求产生A, B, C, D, E
的输出!
这是一个服务器,因此listen
函数进行你所认为的行为,它监听一个特殊的端口。(它的参数和纯node的listen
方法是一样的)。
1 | app.use(function *(next) { |
当一个新的请求到达时,它开始流经中间件,以你所编写的顺序执行。因此在示例中,请求触发了第一个中间件,它输出A
,然后到达yield next
。当一个中间件到达yield next
,它会走向下一个中间件直到离开。因此我们到达第二个中间件它输出B
。然后又跳转到最后一个C
。没有更多的中间件了,我们完成了下游流程,现在我们开始返回到之前的中间件(就像一个栈),D
。然后第一个中间件结束,F
,然后我们成功的完成了上游。
在这一点上,koa
模块自身并没有包含任何其他的复杂性 - 因此我们不拷贝/粘贴已经很完备的Koa站点的文档,你可以再那里阅读。这里是这些部分的链接:
让我们看一个例子(也是来自于Koa的站点),它使用而来HTTP功能。第一个中间件计算响应时间。看看你能够多么容易地接触到响应的开始和结束,多么优雅地分离这些函数行为。
1 | app.use(function *(next) { |
完成
现在你已经熟悉Koa的核心了,你可以说你的旧web框架已经做了所有其他有用的事情并且你需要它们。但是也请记住那里还有数以万计的功能你从未使用过,或者还有一些工作并未按照你想象的方式工作。这就是Koa以及现代node框架好的方面。你可以从npm
中以简短模块的方式向你的应用添加需要的功能,并且它会完全按照你需要的方式运行。
在下一章,我们会看到,使用Koa以上述哲学创建一个网站是多么简单。再那之后,再使用这些你已经了解的知识来感受一下Koa和它的自然感吧。