支持原创,本文为转载文章,转载是为了备忘或丢失,这么好的文章。

https://www.jianshu.com/p/3806417a1991?from=timeline

前言

跟好朋友打赌,我要来个技术文章日更。于是,我跑到到群里喊了句,我要日更。没想到,得到的是大家的支持与鼓励。感谢小伙伴们,逼着我上了梁山......
此文,就是我日更文章的开始,不知道自己能坚持多久。最开始打算将文章标题名定为《围绕node60天》,一个叫老张的网友看了一下,随口说了句短小搓...呵呵呵...短小搓是什么鬼?于是,我给文章起了个高大上的名字,《诺的那些事》......这次够高大上了吧,哈哈哈哈。本来想给浅谈我眼中的express、koa和koa2定为副标题的,可恨简书本着回归写作根本的理念,不存在副标题这个功能,饮恨了。

我是个node程序开发者。此前,我一直认为自己是一个坚定的java信徒,我感觉java才是最终改变世界的语言,甚至我出国旅游去的都是java island......在用了7年Java之后,我遇见了node。遇见node的那一瞬间,我好似看见了蜂腰肥臀的妙龄少女,一群群一片片的在我面前欢歌笑舞,我知道,是时候放弃java了,java就这样渐渐成了往事。不过,我跟java肯定还是藕断丝连的,毕竟hadoop这样的程序还是需要用java来写的,另外,7年的武功是说什么也忘不了了。到现在为止,我用了3年node,见证了node的成长,也见证了自己的成长。我准备好好说说node的那些事,跟大家分享,接受大家的意见和建议。

Nodejs-logo

跟很多人一样,我是以express开启自己的node之旅的。express是什么呢?它是一个封装了Connect的、并提供web服务的中间件,是开发web程序的利器。express是由TJ大神开发的,之后,TJ大神又开发了koa这款神器。但是,因为,es7的飞速发展,koa又迅速衍化出了koa2这个版本,时至今日,koa的github已经全面更换为了koa2版本的代码,当然,这一切,还真就是在我眼前发生的,作为历史的见证者,我要谈谈我对这几个框架的看法。

说个题外话,我的文章,不打算走传统技术文章的套路,我讲就讲一些不一样的,讲一些平常你看不到的东西,希望各位技术大牛多多给小弟指点,在下这厢有礼了。

酷事

单田芳老爷子,有几部超级好听的长篇评述,叫三侠五义,其中,有个重要的人物,白眉大侠徐良(刀是什么样的刀,金丝大环刀,剑是什么样的剑,闭月羞光剑......),白眉大侠徐良是一个早产儿,从小体弱多病,但是最终凭借着刻苦努力,成为了一代武术宗师。node的经历跟白眉大侠很像,node也是个早产儿。早期的node问题多多,那个时候,在win上安装node简直就是一件灾难。不过,随着时间的推移,node变得越来越好用,node的好基友npm也变得越来越庞大。我从node4.0开始入门,后来经历了node6.0版本的各种无奈和妥协,紧接着就迎来了node7.6版本的绝地反击,直到现在,感受到了node7.9的大彻大悟。

记得当初和一个技术猿聊天,他跟我抱怨,node里全是大坑。我一听,这位仁兄用的是express吧,这位仁兄告诉我,没有,他们自己实现了个轮子,跟express差不多,现在正在考虑着升级的事宜呢。呵呵呵了,造了个轮子,还跟express差不多。不过,这也从另外一个侧面看出了node当年不可回避的几个问题:

1.node早期就是个极客玩具,高手众多,产品野蛮生长。
2.使用node开发商业软件是一件正在发生的事情。(对了,阿里、腾讯、非死不可、领英这些大佬也都用node重构了一些适合的模块。)
3.那个时候,使用node的同志们不是傻,就是用鸡汤晃点了他们老板。

回调大坑

不过这个仁兄倒是也说出了node的一些痛点,其中,node存在的技术大坑可能大家都遇到过,这些坑是因为node的语言特性导致的。例如,回调大坑,就是这些坑中,最深的一个。

下边是一个回调大坑的代码示例,我们来感受一下:

module.exports = function (param, cb) { asyncFun1(param, function (er, data) { if (er) return cb(er); asyncFun2(data,function (er,data) { if (er) return cb(er); asyncFun3(data, function (er, data) { if (er) return cb(er); cb(data); }) }) }) } 

node本身是异步回调的,通过高阶函数,偏函数实现回调函数。但是,回调函数嵌套过多,会使代码不可阅读、不可描述,那位仁兄说的大坑便是callback hell,翻译过来就是回调大坑,或者说是Pyramid of Doom,邪恶金字塔。(我朴素的认为这位仁兄只遇到了这一个大坑.....呵呵呵)

回调大坑怎么解决呢?es5可以利用一下第三方库,例如async库,或者单纯使用connect中间件提供的next功能来处理,还可以利用promise来处理回调大坑。当然,单纯使用promise可能给自己带来另外一个大坑,then大坑,或者叫pipe大坑,无数个then,想想也是够恐怖的。另外,还可以使用node自带的事件模块来处理回调问题,利用事件代理(我记得是backbone的一个模块)来简化代码书写。关于事件模块,我之后会写个小专题,来说说node的事件原理。不过,虽然提到了事件模块,但是,我不推荐用事件去处理回调嵌套,因为,需要写更多的代码,得不偿失。

这里说个题外话,在朴大人(朴灵)的一篇文章中,提到了wind库和step库,此处就不进行介绍了,因为,es6和es7会给我们更加好的使用体验。

es5讲完了,各种基于es5来处理回调的方法也讲完了。其实,我在使用这些方法来简化回调嵌套的时候,总感觉是脱了裤子放屁,讲真,有的时候,不仅没有简化代码,还会造成其他的代码阅读障碍,增加团队的学习成本。归根结底,我们的代码是写给人看的,机器只是顺便执行一下而已。

ES的官方组织,肯定认识到了这一点,于是,基于协程原理的规范也呼之欲出,终于在ES6中为大家带来了Generator函数。

Coroutine,协程,简单来说就是由用户通过特定的程序语言控制CPU切换和挂起进程(Process)或者线程(Thread),用同步的方式来模拟异步程序,我之后会单独讲一下进程、线程、协程,在此不做过多展开。既然提供了协程的功能,那么我们处理起回调也就迎刃而解了。

Generator函数和yield语句是一对好基友,如果没有yield语句的话,Generator函数只不过是暂缓执行的状态机而已。通过配合yield,Generator 函数就可以暂停执行和恢复执行,从而将其内部封装的异步函数变为同步执行。下面我们看看例子来感受一下:

function* gen(x){ var y = yield x + 2; return y; } var g = gen(1); g.next() // { value: 3, done: false } g.next(2) // { value: 2, done: true } 

当然Generator函数还有些滥用之嫌,具体为什么,我会在后续的文章中做出解释。反正,ES官方组织他们对于Generator函数是不满意的。于是,ES官方组织马不停蹄,终于在ES7规范中,捣鼓出来了async/await这个目前为止,异步回调最佳的解决方案。

本质上讲,async/await规范是Generator函数+yield语句的语法糖。返回部分都是一个Promise对象。async/await规范比Generator函数+yield语句要更加好用,下面我们看看例子来感受一下:

var sleep = function (time) { return new Promise(function (resolve, reject) { setTimeout(function () { resolve(); }, time); }) }; var go= async function () { console.log('start'); await sleep(3000); console.log('end'); }; go(); 

至此,回调大坑的问题算是得到了很好的解决,我们接下来,就说是express、koa和koa2这三个框架。

TJ大神的三大英雄

TJ大神

每每看到TJ大神的头像,我都会想起一个词:preconception。偏见,先入之见。许多人,对于程序员是存在很大的偏见的。大多数人的脑海中给程序员的定义都是这个样子:

图片来源于网络,加班的程序员们

一般人认为程序员:不够健康,不够整洁,不够潮流,人傻,钱多......TJ大神,这个顶级程序员,则给我们上了非常生动的一课。TJ是设计师出身,半路出家做了程序员,他一个人完成了express、koa、koa2设计和核心开发。TJ曾经说过,他之所以能做出这些NB的软件,是因为,他热爱阅读其他大牛的源码,他会把自己不明白的问题都弄懂。他在第一时间遇见了问题,处理了问题,保证自己深刻理解各种软件的核心原理和运行机制。于是,TJ就变成了一个npm包贡献极多的node大神,他的光辉和事迹最终会变为传说,再node圈里永久的流传下去......

三大英雄

node的早期,是荒芜的年代,正如之前我的那个哥们一样,那个时候,没有轮子。程序员自己制造了各种各样的轮子,真可谓是八仙过海,各显神通。那个时候node程序员一般这样开始写web应用:

var http = require('http');http.createServer(function (request, response) { response.writeHead(200, {'Content-Type': 'text/plain'}); response.end('Hello World\n'); }).listen(8888); console.log('Server running at http://127.0.0.1:8888/'); 

终于,TJ打造了express、koa、koa2三大英雄,node的浪漫主义年代逐渐揭开了序幕。我们看下边的表:

英雄 说明 对应 经典
express web框架 es5 回调嵌套
koa web框架 es6 Generator函数+yield语句+Promise
koa2 web框架 es7 async/await+Promise

下面我就开始说一下这三个框架和他们之间千丝万缕的联系

初代英雄:express

初代英雄:express

express的入门非常简单,通过创建express的Application就构建了一个expressweb实例。下面我们看看例子来感受一下:

var express = require('express');
var app = express(); app.get('/', function (req, res) { res.send('Hello World!'); }); var server = app.listen(3000, function () { var host = server.address().address; var port = server.address().port; console.log('Example app listening at http://%s:%s', host, port); }); 

express本身封装了路由模块,因此,可以利用express直接处理各种http路由请求。

在express用四个主要模块:

模块 说明 解释
Application web服务器模块
Application

抽象了web服务器的主要贡呢和接口,如监听、事件、加载中间件、get\post请求等

Request 请求
Request

Response 响应
Response

Router 路由
Router

express用Application、Request、Response、Router四个主要模块,模拟了一个完整的web服务器功能,对了,express还在相当长的一段时期中受到了Connect的影响。在使用express的过程中,你会发现express是一个极简的、灵活的 web 应用开发框架,它提供的这一系列强大的特性,可以帮助你快速创建各种 web 和移动设备应用。

二代英雄:koa

二代英雄:koa

目前的koa官方github已经全面的使用koa2版本的代码了,换句话说,koa和koa2现在只是版本上的区别了,koa是老版本,koa2用新的版本号。因此,koa1,我们需要查看老的代码版本。

koa 是由 express原班人马打造的(TJ),致力于构建更小、更富有表现力、更健壮的 web 框架。使用 koa 编写 web 应用,通过组合不同的 generator,可以免除重复繁琐的回调函数嵌套,并极大地提升错误处理的效率。koa 不在内核方法中绑定任何中间件,它仅仅提供了一个轻量优雅的函数库,使得编写 koa 应用变得得心应手。

Koa 包含了像 content-negotiation(内容协商)、cache freshness(缓存刷新)、proxy support(代理支持)和 redirection(重定向)等常用任务方法。 与提供庞大的函数支持不同,Koa只包含很小的一部分,因为Koa并不绑定任何中间件。

koa中也包含4个主要模块,Application、Request、Response、Context。此时,router已经被排除在内核之外了。其实,koa只是一个“中间架”,几乎所有的功能都需要由第三方中间件来协同完成。例如koa的router模块,就有20多个,优胜劣汰,自由选择......虽然有不规范之嫌,但是,koa是规范的这就足够了。使用koa,可以最大限度的发挥自己的想象力,利用koa,构建各种个性化的web与移动应用。下面我们看看例子来感受一下:

var koa = require('koa');
var app = koa(); app.use(function *(){ this.body = 'Hello World'; }); app.listen(3000); 

没错,就是这么简单,使用了Generator函数,这也是koa和express最大的不同,express是回调函数,koa是用Generator来作为响应器的。

另外,那个替代了router的context是怎样的呢?下面我们看看例子来感受一下:

app.use(function *(){this; // is the Context this.request; // is a koa Request this.response; // is a koa Response }); 

另外,koa中还有co这个工具。co是一个“皮”,通过co来包装Generator和yeild,下面我们看看例子来感受一下:

var co = require('co');co(function *(){ // yield any promise var result = yield Promise.resolve(true); }).catch(onerror); co(function *(){ // resolve multiple promises in parallel var a = Promise.resolve(1); var b = Promise.resolve(2); var c = Promise.resolve(3); var res = yield [a, b, c]; console.log(res); // => [1, 2, 3] }).catch(onerror); // errors can be try/catched co(function *(){ try { yield Promise.reject(new Error('boom')); } catch (err) { console.error(err.message); // "boom" } }).catch(onerror); function onerror(err) { // log any uncaught errors // co will not throw any errors you do not handle!!! // HANDLE ALL YOUR ERRORS!!! console.error(err.stack); } 

虽然,前边说了很多express、koa的相关知识,但是,这两个都不重要了,随着koa2的扶正和node 7.6的发布,基于nodejs的程序开发,开启了新的篇章。

三代英雄:koa2

三代英雄:koa2

上一节已经提到,目前的koa官方github已经全面的使用koa2版本的代码了,并且有一句非常重要的提示Koa requires node v7.6.0 or higher for ES2015 and async function support.。意思是说,koa需要至少node v7.6.0版本和ES2015(es6+async)才能使用。这个提示,也是非常重要的一句话,从这个版本开始,我们可以抛弃Bable(当然,nodev7.6还是不能完全抛弃babel,因为到目前为止,node都还没有实现对import和export的支持,感谢深蓝wbe的提醒),快乐的使用async等新的语法了。(Babel 自带了一组 ES2015 语法转化器。这些转化器能让你现在就使用最新的 JavaScript 语法,而不用等待浏览器和node提供支持。)

目前,koa2结合了async/await已经成为了最好的web开发框架。上一节,已经讲了koa的主要模块和实现原理,此处,我只是简单说说koa2和koa不同之处,下面我们看看例子来感受一下:

const Koa = require('koa');
const app = new Koa(); app.use(ctx => { ctx.body = 'Hello World'; }); app.listen(3000); 

函数式编程,async/await功能,程序简单,好用,真可谓是居家旅行的不二之选呀。通过查看代码,koa2去除了co中间件,进一步的精简了内核,这一点也正好符合当下性冷淡风格的设计潮流......不禁想赞叹一句,TJ不愧是设计师出身呀......

小结

其实,很多人不关心框架的原理,他们关心的是如何从express升级到Koa,如何从koa升级到koa2。虽然koa
对于向前兼容的并不好,但是,我在这里想提出另外一种思路,就是利用express+async/await的形式来做升级。一方面,可以在不改变原有程序的基础上使用最新的语法特性,另一方面,可以用最小的代价获取最大的效益。下面我们看看例子来感受一下:

var PageQuery = async (page, pageSize, Model, populate, queryParams, sortParams) => {var start = (page - 1) * pageSize; var $page = { pageNumber: page }; let TotleRow = await ModelCount(Model, queryParams); let records = await PageRecords(Model, queryParams, start, pageSize, populate, sortParams); $page.TotleRow = TotleRow;//(count - 1) / pageSize + 1; $page.PageCount=parseInt(TotleRow/pageSize)+1; $page.results = records; return $page; }; var ModelCount = (Model, queryParams) => { return Model.count(queryParams).exec().then((count) => { return count; }).catch((err) => { console.log("err:" + err); return err; }); } var PageRecords = (Model, queryParams, start, pageSize, populate, sortParams) => { return Model .find(queryParams) .skip(start) .limit(pageSize) .populate(populate) .sort(sortParams) .exec() .then((doc) => { return doc; }).catch((err) => { console.log("err:" + err); return err; }); } //...... Customer.PageQuery(pageNum, pageSize, Customer.Model, "", {}, {}).then((pageResult) => { res.render('customersList', { layout: "admin", customersList: pageResult.results, totalPages: pageResult.PageCount, pno: pageNum, }); }).catch((err) => { console.log("err:" + err); res.send("err"); }); 

上边是我写的一个中间件,可以通过这种简单的方式,来处理express与es7的升级问题。(完整代码可以到我的github上去查看https://github.com/lxlhum/meet_quick ,大家帮我把星星点起来哈)

尾声

流行的web技术统计:node、ruby、python、php、java

现在,node的社区非常活跃,产品换代升级非常迅速和及时。使用node,既要求我们用扎实的功底,又要求我们与时俱进,不断学习。毕竟,不管用什么语言,在程序开发的道路上,只有不断学习,才能不断前进。

这部分关于node的基础知识,可以看我写的一个笔记:深入浅出NodeJS的读书笔记,保证您读过以后,会有豁然开朗之感。笔记中,记录了tcp/ip,http,socket/websocket的相关知识,全方位的介绍nodejs。

转载于:https://www.cnblogs.com/saveme/articles/9914911.html

三英战豪强,思绪走四方。浅谈我眼中的express、koa和koa2相关推荐

  1. 三英战吕布?微信一个字,封!

    "为了记住这一天,我们专门做了一个网页.你只要在浏览器中输入 20190115.t.tt 就能下载包括聊天宝在内的这三款软件." 这是今晚由老罗主讲的快如科技 2019 发布会发布 ...

  2. 三国演义与设计模式之Decorator模式(1.虎牢关三英战吕布 2.云长降曹受封赏)...

     写在前面: 以下三点,适用于本系列所有文章. 1.同一个故事,从不同的角度看,就可以引申出不同的模式.本系列中所举模式,未必是当前故事是匹配的,还望大家多提意见,一起讨论,一起提高. 2.类图部分只 ...

  3. 《三英战吕布》 - 图像模板匹配 【Python-Open_CV系列(八)】

    <三英战吕布>- 图像模板匹配[Python_Open_CV系列(八)] 文章目录 1.什么是模板匹配? 及 模板匹配方法matchTemplate() 介绍 素材准备 2.单模板匹配 2 ...

  4. 三英战吕布:360与金山、腾讯、百度之间的恩怨情仇

    三英战吕布:360与金山.腾讯.百度之间的恩怨情仇 近日,腾讯金山等企业发布联合声明反对360不正当竞争,而360称腾讯发声明是为转移视线,将公布更多证据.这是继<狗日的腾讯>的" ...

  5. 继三英战吕布之后,只有他敢卷土重来

    点击上方"逆锋起笔",选择"星标" 我们一起「在看」 作者:你未读 整理:君未读 移动社交的硝烟从未停止过... 2018.08-三英(躲闪,马桶TM,子弹短信 ...

  6. 浅谈黑客眼中的心理学

    由于个人对计算机比较痴迷,对黑客比较感兴趣,所以关注这方面信息将近两年啦,今天借此机会,浅谈一下黑客眼中的心理学. 也许你对"黑客"这个词并不是很熟悉,但是你或多或少应该听说过这么 ...

  7. 主板噪音测试软件,工作噪音测试 - 三英战吕布?四款300元热门电源横评 - 超能网...

    ◆ 工作噪音测试(Operation Noise Test) 噪音的标准是根据听力正常的人能听到的最小声音而定,0分贝为刚好能听到的声音,每增加10分贝等于强度增强10倍,增加20.30分贝则为100 ...

  8. 3Q大战再起闪现“三英战吕布”?

    联想集团终于在巴西这个全球第三大PC市场有所突破了! 这一天,联想集团掌门人杨元庆等了四年! 2008年联想集团曾想通过收购巴西第一大PC厂商Positivo在巴西市场取得先机,但数次波折过后,杨元庆 ...

  9. 多闪、马桶MT、聊天宝 三英战吕布?

    这一周,三款社交软件的发布可谓本周的热点事件.我来谈谈对这三款软件的一点个人看法,不喜勿喷. 三款软件"不约而同"选择了在一天露脸,这热点效果x3.社交软件霸主微信现在的用户数已经 ...

最新文章

  1. android密码解锁/指纹解锁返回的authToken深度解剖
  2. Python: 大型数组运算
  3. Java基础day4
  4. 在大规模系统中使用Scala
  5. Something haunts me in Python
  6. WPF 中Frame + Page 的使用
  7. 使用ganglia监控hadoop及hbase集群
  8. leetcode912. 排序数组 有范围的排序统统用桶排序
  9. python读取文件中的内容_python 读取文件夹中的文件内容
  10. python3缺少pip_Ubuntu中找不到pip3命令的解决方法
  11. 解决scanf_s函数报错:没有为格式字符串传递足够的参数
  12. 容器编排技术 -- Kubernetes 给容器和Pod分配CPU资源
  13. pytorch---之torch.manual_seed()
  14. 【转帖】防止ASP.NET按钮多次提交的办法
  15. C#--反汇编工具ildasm.exe
  16. 文献阅读|Nomograms列线图在肿瘤中的应用
  17. 调度工具之Azkaban 介绍
  18. (demo)springboot接口suger_整合_hbase+phoenix
  19. 如何一周之内摸清一个行业?
  20. JavaWeb——EL 函数

热门文章

  1. Web分辨率以及网页测试
  2. 《JavaScript 高级程序设计》
  3. 别什么东西都在淘宝上买
  4. 机器学习 线性回归 以及评估训练结果 (二)
  5. java EE与java SE的区分
  6. Unraveling Bezier Splines 
  7. Python实战例子(32个附源码)
  8. 读书笔记_《核心算法与视觉实践》冯超.电子工业出版社
  9. 驱动万物 AliOS加速汽车操作系统普及
  10. 《慢性子裁缝和急性子顾客》原文