说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

【深入浅出Koa】常用工具分享 帮你降低编程难度

HTML文档下载 WORD文档下载 PDF文档下载
Koa由Express的原班人马打造的,小而美,并以一种现代化开发方式构建Web应用。本文为【深入浅出Koa】系列文章第二篇,主要介绍可降低编程难度的工具,及Koa的基本特性和运行机制。

在前一篇 入门知识文章中,我们学习了很多关于生成器的知识,借助于生成器,我们可以在编写异步代码时使用同步代码风格, 这样做能够简化异步编程,因为同步的代码更加简单,优雅,也更可靠,而异步代码则可能会将我们引入回调地狱中。

在本文中我们会介绍一些能够降低编程难度的工具,因此会着重介绍其中最有趣的部分。此外, 本文还会介绍Koa的基本特性和运行机制。

简单回顾

// First partvar thunkify = require('thunkify');  var fs = require('fs');  var read = thunkify(fs.readFile);// Second partfunction *bar () {    try {    var x = yield read('input.txt');  } catch (err) {    console.log(err);  }  console.log(x);}// Third partvar gen = bar();  gen.next().value(function (err, data) {    if (err) {    gen.throw(err);  }  gen.next(data.toString());});

这是 前一篇文章中的最后一个例子,正如你看到的那样,我们可以将程序分为三个重要部分。 首先,我们需要创建了一个被thunk化的函数,我们将在生成器中使用到这个thunk函数。 然后,我们可以编写我们的生成器函数,并在函数中使用前面创建的thunk函数。 最后,我们调用并遍历生成器,并进行错误处理等工作。如果你仔细的考虑了这个过程, 你会发现最后一个部分和整个程序的核心内容并没有太大的关联。它只不过是用来让我们运行生成器而已。 因此,我们可以利用一个工具来简化这个过程,幸运的是,正好有一个这样的模块,它就是co。

co

Co是一个基于生成器的Node流程控制模块。下面的例子所做的工作与前一个例子完全一样, 但是我们没有直接编写调用生成器的代码(上面代码的第三部分)。取而代之的是,我们将生成器直接传递给了co函数, 然后立即调用这个函数,任务就这么神奇的完成了。其实,也没什么神奇的,co只不过是帮你完成了生成器调用代码而已, 因此我们没必要担心下层的工作。

var co = require('co');  var thunkify = require('thunkify');  var fs = require('fs');var read = thunkify(fs.readFile);co(function *bar () {    try {    var x = yield read('input.txt');  } catch (err) {    console.log(err);  }  console.log(x);})();

正如你已经知道的那样,你可以在yield后面跟上任何你需要计算(用于获取某些值、执行某些任务)的表达式。因此, 不仅仅是thunk函数可以跟在yield后面。由于co主要用来创建更简单的控制流,因此它只能用来yield一些特定类型。 目前主要可以在co中被yield的类型有:

  • thunks(函数)
  • 数组(并行执行)
  • 对象(并行执行)
  • 生成器(代理)
  • 生成器函数(代理)
  • Promises

前面我们已经讨论了thunks是如何工作的,因此下面我们来讨论一些其他内容。

并行执行

co(function *() {    // 3 concurrent reads    var reads = yield [        read('input.txt', 'utf-8'),        read('input.txt', 'utf-8'),        read('input.txt', 'utf-8')    ];    console.log(reads);    // 2 concurrent reads    reads = yield {a: read('input.txt', 'utf-8'), b: read('input.txt', 'utf-8')};    console.log(reads);}).catch(onerror);

如果你yield了一个数组或对象,它会并行的计算数组或对象中的内容。当然,如果集合中的内容为thunks或生成器, 它也能同样进行处理。并且你也可以进行嵌套,它能够便利你的数组或对象,然后并行的执行工作函数。需要记住的是: yield后的生成的结果并不是扁平的,而是保持和原来相同的结构。

co(function *() {    var a = [read('cinq.txt', 'utf-8'), read('deux.txt', 'utf-8')];    var b = [read('six.txt', 'utf-8'), read('un.txt', 'utf-8')];    var files = yield [a, b];    console.log(files); // [ [ 'cinq', 'deux' ], [ 'six', 'un' ] ]}).catch(onerror);

你也可以在thunk调用后进行yield,同样能达到并行的目的。

co(function *() {      var a = read('input.txt', 'utf-8');    var b = read('input.txt', 'utf-8');    // 2 concurrent reads    console.log([yield a, yield b]);    // or    // 2 concurrent reads    console.log(yield [a, b]);}).catch(onerror);

委托

前面说过,你也可以在yield后面跟上生成器。注意你可以不必使用yield *。

var stat = thunkify(fs.stat);function *size(file) {    var s = yield stat(file);    return s.size;}co(function *() {    var f = yield size('input.txt'); // hello world    console.log(f); // 11}).catch(onerror);

我们大致尝试用co处理了每一种可以被yield的类型。下面我们来看最后一个例子,算作总结。

var co = require('co');var fs = require('fs');function size(file) {    return function (fn) {        fs.stat(file, function (err, stat) {        if (err) return fn(err);        fn(null, stat.size);        });    }}function *foo() {    var a = yield size('un.txt');    var b = yield size('deux.txt');    var c = yield size('trois.txt');    return [a, b, c];}function *bar() {    var a = yield size('quatre.txt');    var b = yield size('cinq.txt');    var c = yield size('six.txt');    return [a, b, c];}co(function *() {    var results = yield [foo(), bar()];    console.log(results);}).catch(onerror);function onerror(err) {    console.error(err.stack);}

我想目前为止你应该能够对生成器有了一个较为清晰的认识了,并且能够借用co很好的处理异步控制流。关于co本身, 如果你想了解的更深入些,可以阅读它的源代码。现在,我们将重点移到Koa本身上来。

Koa

对于Koa而言,你需要知道的并没有很多。如果你阅读了它的源代码的话,你甚至会发现总共才4个文件,每个才300行左右。 Koa遵循了每个程序只做一件事并将其做的更好的原则。你会发现,每个优秀的Koa模块都非常的紧凑,并且只做一件事, 并且在其他模块的基础上进行构建。你应该记住这一点,并使用这个方法来开发你自己的Koa模块。这将会有益于所有人, 也有助于你和其他人阅读源代码。先记住这一点后,然后我们来看看Koa的一些核心特性。

应用 Application

var koa = require('koa');var app = koa();

创建一个Koa应用只不过是在调用一个相关的模块函数而已。它会提供给你一个对象,这个对象包含一个生成器数组 (一组中间件),对收到的每个请求,它会使用一种堆栈式的方法执行。

级联 Cascading

当你使用Koa时,一个非常重要的术语是中间件。现在让我们来搞清楚这个概念。

Koa中的中间件是一组用于处理请求的函数。使用Koa创建的服务器,可以有一组堆栈结构的中间件与它关联。

级联在Koa中意味着:控制流会流经一组中间件。在web开发中这个概念非常的有用,你可以将复杂的行为借助于这个手段变得简单。 Koa通过生成器函数来实现这一点(中间件级联),并且更具创新性和简洁性。 它能够yiled下游中间件,之后控制流再返回到上游中间件。 将生成器加入到控制流中非常简单,只要在调用use()方法时使用生成器即可。 猜猜下面的代码为什么每次接收到请求时会输出的是A, B, C, D, E。

下面的代码演示了一个服务器,因此listen方法用于监听一个具体的端口:

var koa = require('koa');var app = koa();// 1app.use(function *(next) {    console.log('A');    yield next;    console.log('E');});// 2app.use(function *(next) {    console.log('B');    yield next;    console.log('D');});// 3app.use(function *(next) {    console.log('C');});app.listen(3000);

当一个新的请求进来的时候,它会流经一系列的中间件(即按照use方法调用的顺序1-2-3)。因此在上面的示例代码中, 请求首先经过第一个中间件,它会首先输出A,然后它遇到了yield next语句,这会使它转入下一个中间件计算相应的结果, 只有在处理完后才回到离开的地方。因此,接下来会转入到下一个中间件打印B,再次碰到yield next, 转入下一个中间件,打印C。现在已经没有更多的中间件了,因此执行完第三个中间件就会回流,首先回到第二个中间件, 继续执行打印出D,中间件2的代码执行完毕,再回流到第一个中间件,打印E。

到目前为止,Koa模块本身并没有什么复杂的地方,因此没有必要再追溯那些你可以在文档中就能知道的信息。 我推荐你直接去阅读Koa的文档去了解关于Koa的详细使用说明,其实也没有什么复杂的内容,所以这里也就不再多介绍了。 这里列出相关文档的链接:

  • Context
  • Request
  • Response
  • 其他

最后让我们再来看一个例子(这个例子来源于Koa的官网),它利用了一些HTTP特性。第一个中间件计算了响应的时间。 你会发现获取响应开始和结束的时间非常简单。并且在Koa中你可以优雅的将这些功能模块分离开。

app.use(function *(next) {      var start = new Date;    yield next;    var ms = new Date - start;    this.set('X-Response-Time', ms + 'ms');});app.use(function *(next) {      var start = new Date;    yield next;    var ms = new Date - start;    console.log('%s %s - %s', this.method, this.url, ms);});app.use(function *() {      this.body = 'Hello World';});app.listen(3000);

总结

现在你已经熟悉了Koa的核心内容, 虽然使用旧的框架也能够完成相关的任务,但是现在你可以尝试Koa这个新的框架来解决以前的问题。因为, 在旧的框架中可能有非常多的功能是你从来都用不到的,或者某些并不是按照你的设想工作的。 现在,以Koa为代表的现代Node框架能够为你带来这些改变。你可以使用更轻量级的核心, 然后通过npm引入你需要的模块到你的app中,这种方式下你能够完全的控制哪些模块是你需要用的。

Links

  1. Koa的一些例子
  2. 中间件列表
  3. Koa最佳实践指南

原文地址:Getting Started with Koa - part 2

译者简介:景庄,前端工程师,关注Node.js、前端工程化。个人博客: http://wwsun.github.com。

 相关阅读:

【深入浅出Koa】入门知识,带你以现代化开发方式构建Web应用

欢迎加入CSDN前端交流群2:465281214,进行前端技术交流。  

将图片「非重叠显示」填满整个表格视窗 -VB资料 将英文字母及阿拉伯数字旋转任意角度 -VB资料 将真彩色图像变为256色灰度(BIG5码):-VB资料 VB利用Image控件实现图形浏览程序 利用VB捕捉并保存屏幕图象 切割一个Container中的图片 -VB资料 VB如何改变桌面的图片? VB如何实现“百叶窗”的图形特效? VB如何实现霓虹灯效果 VB如何在VB中用API获得EXE文件图标并显示在Picture控件里 VB如何在VB中直接显示无格式256灰度级图像 VB如何在窗体中平铺图片? 三维字的实现 -VB资料 闪动窗口标题 -VB资料 闪烁的标题栏 -VB资料 实现画面的各种切换方法-VB资料 实现屏幕变暗的效果 -VB资料 实现图像切换效果 -VB资料 提取Win9x拷贝的动画-VB资料 一个图像滤光处理程序-VB资料 一个用VB5.0 实现的鼠标绘图程序 用VB6.0制作画图板 用VB6设计有趣的动画场景 用VB编程绘制网格图像 用VB绘制抛物线动画曲线 用VB绘制正弦动画曲线 用VB实现“百叶窗”的图形特效 用VB实现托盘动画图标 用Visual Basic 定制BMP文件 用Visual Basic的Move方法实现动画效果 用Visual Basic与MS-Draw开发通用作图软件 怎么将vc程序编译成ocx控件,供vb调用! 一个奇怪的问题。 请问在c#如何把char转换为相应byte[](中英文混合) 请高手帮忙------怎样读取sql server 中类型为ntext的数据并显示在页面上?? 请问如何用VB script写一个telnet 登录脚本? 谁有《Active Server Page & Web 数据库》的范例? 关于C++ 有关数据库方面的问题! 如果判断两个用户连接同一张表,而让同一时刻只让一个用户访问???求救 请问use case描述中的扩展点是什么意思?谁给我诠释诠释!100分送上!不够再加! XX去桂林…不能同去,不爽散分儿! 交流VB 放假了,各位兄弟帮帮忙吧。改了ip,不能建立新的数据库了。 急切求教:关于sql全文检索 如何在状态条中动态显示字幕 请教高手:关于定时/计数器 如何在WIN98下面安装WIN2000双启动,需注意什么? 简单问题,在线等 jsp打印设置 scriptx 怎么用lotus script打开一个表单 交流VB Microsoft Windows 2000 Professional 如何安装终端服务? adsi建的邮箱,用outlook连接exchange必须输入username@domain.com格式的帐号才能登陆,请问怎么解决? 如何实现一个任意长度的C++整型类? 一个关于ADO连接,打印报表的问题. Microsoft Windows 2000 Professional 如何安装终端服务? 从注册表中读信息 100分!!为什么我做完fla文件后,生成影片时FLASH自动提示把我的文字打散,请问各位怎么解决??? Microsoft Windows 2000 Professional 如何安装终端服务? 一个奇怪的现象:Delete键在TextBox中失灵 怎么样屏蔽键盘上的print screen键? 为什么一调用office就死机? 谁有Ide.sys、cdrom.sys这两个文件和两个文件的原代码啊! 请问: 当J2EE开发C/S模式时,我的C端要不要装J2EE平台啊?(在线等) 局域网中,一些电脑可以PING通局域网内所以电脑的IP,但是网站邻居就是无法查找到? 委托中要求进行参数传递,应该怎样做,谁帮帮我? *>>--谁做过日历以及日历相关-- 如何卸载windows 2003 server,再重新安装windows 2000 server? 请问将Interbase中两个Varchar型字段连接起来的查询语句怎么写? 域名设置问题?? 为什么微波和X光能穿透介质,而波长介于它们之间的可见光恰不能? 生成EXE问题! Transaction Data Module 和 ADO 问题 寻求DOMINO SERVER 得配置资料!如HTTP的配置等等。 怎么创建dll?创建dll时参数应该怎么定义?创建后怎么调用?在哪儿声明? 熟悉ADODB.Stream的大侠看过来! 在WIN32 CONSOLE APPLICATION 建立的程序中为什么不能使用CString 类 数据库恢复的简单问题 谁用过jfreereport或jaxperreport做过报表?各位大哥帮忙呀!!!--就20分了 紧急高分求助:怎么在windows的user control中加一个参数 [求助]怎样让工程加入Data Report ,菜单 工程 里没有添加Data Report 的呀? 钙化灶的原因是什么? 请问钙化灶是什么意思?_头痛 钙化灶是什么病 为什么水手以前听到过,星星点灯怎么那么少听到呢,我听过了我很喜欢,但是为什么就不出名呢 衡阳市蔡伦大道是从那个路口到那个路口,怎么在地图上找不到.新汽车中心站说是在船山大道与蔡伦大道相交 肝内胆管结石或钙化灶需要怎么治疗? 求视频:丑恶的近义词是什么 湖南省衡阳市立新大道属于衡阳市的哪个区 星星点灯是什么啊? 兜风耳:”古语两耳兜风,败家祖宗,其实未必,主性反叛、硬颈“ 这句话翻译成白话怎么说 提升信任感亦可靠食补铁托遗孀落葬德媒曝美监听站遍布全球沙特女性“要开车”伊朗边防军遭伏击 处决16名反叛者德媒曝美监听默克尔十余年法一残障者本周跳伞飞越珠峰奥巴马3年前已知监控默克尔 美曾要求印度筹谋在中巴边界建14条铁路线用于菲律宾:对香港人质事件赔款不用公款 伊拉克汽车爆炸 一日致死56人如何逛好教育展 迈出成功留学第一步?缅甸沉船28人丧生《唱唱歌、跳跳舞》 中老年朋友来一试小康家庭不动产投资意愿下滑日本研讨天皇退位如他一般“自觉”,在日常中超越自我Fintech大佬解局互联网金融蜕变国足新主帅本周揭晓去哪儿网与航司全面恢复合作 多项“黑杨浦后年将建成“双创”示范基地康宝莱牵手特奥会
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘