Romennts 致力于成为最会弹钢琴的架构师

大话node.js web开发重点知识概要,帮你从入门到熟悉(严肃脸)

2017-03-29
Romennts

前言

本文是在看完朴灵大师的著作《深入浅出node》写的一些总结,更多的可能是从web开发者的角度去思考,过于底层的概念会选择性的略过,或者只说我在开发过程中遇到那些由于底层认识浅显产生的坑。另外由于本书是在2013年写的,很多著名框架那时候还没有,书中没提及的我会适度穿插一点,所以本文涉及面可能非常繁杂。

不得不说说在去年5月份就入手了这本书,那时候刚刚学了Javascript,对node.js一点认识都没有,后果可想而知。可以说,朴灵大师的这本著作一点都不适合作为node.js的入门书籍。这就要吐槽本书的附录A,深深的恶意啊,既然本书不是面向node的初学者,为什么有“安装Node”这个环节,那时候超级小白的我,看到这个附录就以为这本书是类似于node从入门到精通云云的,虽然买前看到豆瓣也有书评说这本书不适合入门小白。入手后,捧着这本书硬是啃了几天,嚼之无味,果断弃坑,用回Java,期间偶尔用一下Javascript的前端框架了,写一下node Demo,做些爬虫。

时隔半年,写了个小程序上线后,因为众多关于node“谜之错误”,根本原因是不了解内在机理导致的各种囧况。本人有性能强迫症,不想发现一起bug,查处一起bug,我要做的是坚决杜绝~~于是想起本书,翻看几页,平日遇到问题都可以在这里找到原因,以及一些用其他语言开发web程序的坑也有说到,个人感觉本书最赞是第八章——构建web应用,收获颇多,可以单独拿出来再写一本书。看着一发不可收拾,白天在图书馆,夜里挑灯看书,因为大三没有什么课了,前两天还看到天亮,我的天。以前高考都没那么勤奋,也许这就是欠下的迟早都要还。

回到正文干货

单线程

如果你用过Java多线程,第一个Demo大概是买票同步的问题。Node.js 使用的是单线程,不存在这种问题,也就不会产生死锁问题。同时还有异步处理的能力。那为什么单线程,可以异步处理呢?接下来在异步处理会说会说。而单线程也有诸多坏处,例如挂掉了,服务就挂了。无法使用多个CPU资源。可这个嘛,总是有解决的办法的。慢慢看下去

死锁简单说就是,你和一个妹子互相暗自喜欢对方(哦,我当你是男的了),她等你表白,你等她表白,结果一直在互相等待,谁都不想表白先,是不是觉得这个问题很难解决,其实就是你可以敏锐一点,释放表达信号,解锁。

异步处理

异步处理可以说是node.js最大的特点,没有之一噢。上文不是说单线程吗?怎么可以异步呢。其实是这样的:当node.js接受到一个请求,然后发现这个请求需要去读取本地文件的时候,那么node.js就会告诉操作系统,嘿,帮我从硬盘上读取XXX文件到内存,等一下我要用,读取完毕告诉我。

典型的例子,平时妈妈做家务。开了洗衣机之后,就会去做早餐,隔一段时间就会回来看看洗衣机洗完没有,而不会一直在干等洗衣机洗完晾衣服。妈妈还是只有一个,可是她可以“并发”做多件事情噢。

其实从严格上说,Node自身是多线程,可是由程序员写的Javascript代码是单线程的,从上面的例子你应该能看出问题,洗衣机什么时候洗完呢,洗完的话就去晾衣服啦。Node.js用到的是一种事件循环的机制,简单点说就是每段时间就去看看搞定没有。

异步编程

平时我们思维习惯是做完一件事再做一件事,而异步编程先来想要做什么事。作为异步编程程序员,你要想着你是大Boss,有好多秘书,你有一堆事情,这些事情基本都是分发任务,这些事情就让秘书去处理,每一件事完成了秘书会通知你,接下来你就只是处理一下,签个字就好了。假如分发的任务并不是每个都相对独立的,有些呢需要做完A才能开始B,做完B才能开始C,做完C才可以开始D…这时候你自己都会被这种嵌套搞得一团糟。如果是写代码的话是这样的:

	asyncFunA(function(err, a) {
    // do something with a in function 1
    asyncFunB(function(err, b) {
        // do something with b in function 2
        asyncFunC(function(err, c) {
            // do something with c in function 3
				asyncFunD(function(err, d) {
            		// do something with c in function 3
			});
        });
    });
});

如果你是Boss,秘书告诉你A好了B错了,然后你看回对应怎么处理。到底是哪个something else…呢,我都不想看了。问题总会有解决的办法的(我是说编程领域,我可是严谨的程序员)

解决方案:(参考了腾讯全端 AlloyTeam 团队 Blog)

//如最基本的,使用具名函数并保持代码层级不要太深
function fun3(err, c) {
    // do something with a in function 3
}
function fun2(err, b) {
    // do something with b in function 2 
    asyncFun3(fun3);
}
function fun1(err, a) {
    // do something with a in function 1
    asyncFun2(fun2);
}
asyncFun1(fun1);

//或者进阶一级的使用Promise或者链式Promise,但是还是需要不少的回调,虽然没有了嵌套
asyncFun1().then(function(a) {
    // do something with a in function 1
    asyncFun2();
}).then(function(b) {
    // do something with b in function 2
    asyncFun3();
}).then(function(c) {
    // do somethin with c in function 3
});
//使用async等辅助库,代价是需要引入额外的库,而且代码上也不够直观
async.series([
    function(callback) {
        // do some stuff ...
        callback(null, 'one');
    },
    function(callback) {
        // do some more stuff ...
        callback(null, 'two');
    }
],
// optional callback
function(err, results) {
    // results is now equal to ['one', 'two']
});

但是我要介绍个神器: CO库 API (不想写例子了,本文更多篇幅在下文呢) ,相信我,异步变成最终都会和同步编程一样优雅。阮一峰大师也是这么说的。

线程问题

严格来说,Javascript并不是单线程的,除了Node自身其实还有一定数量的系统IO,只不过这部分IO由libuv处理,对于Node使用者是透明的。

  • C10K是什么

Node 与其他语言对比

Node 单线程对多核使用不足的问题

//创建任意端口的进程
var http = require('http')
http.createServer(function(req,res){
    res.writeHead(200,{'Content-Type': 'text/plain'})
    res.end('helloworld\n')
}).listen(Math.round((1 + Math.random())*1000),'127.0.0.1');

fork

记住,fork()的代价是昂贵的,在node里面,这样做是为了充分利用多核资源,而不是为了解决并发的问题

进程监控

//进程监控
var fork = require('child_process').fork;
var cpus = require('os').cpus();

var server = require('net').createServer()
server.listen(1337);

var workers = {};
var createServer = function (){
	var worker = fork(__dirname + '/worker.js')
	worker.on('exit',function(){
		console.log('Worker' + worker.pid + 'exitd')
		delete workers[worker.pid]
		createServer();
	})

	worker.send('server',server)
	workers[worker.pid] = worker;
	console.log('createServer pid' + worker.pid)
}

for(var i =0;i<cpus.length;i++){
	createServer();
}

process.on('exit',function(){
	for(var pid in workers){
		workers[pid].kill();
	}
})

fork

  • 更平滑处理异常工作进程思路:

内存控制

what,深入理解V8虚拟机来了

  • 说说V8的趣事
    • 不可否认JVM是我见过性能最强悍的虚拟机。V8也同样强悍,因为它们的领导者是用一人——Lars Bak
    • 10年之前chrome的市场占有率远远没有目前那么高那么稳定,后来正因为V8 Javascript虚拟机秒杀了同一时间其他虚拟机,使得Chrome开始超越IE,成为浏览器第一

说到这里,你会发现原来Node.js的运行环境是从浏览器的Javascript虚拟机中脱离出来的。也就是说,V8是专为浏览器设计的,导致node使用javascript只能使用部分内存。X64 约为 1.4GB,X86 约为0.7GB,在开发过程中遇到无法读取大文件极有可能是这里限制了,可以在node启动通过传递 –max-old-space-size 或者 –max-new-space-size ,学过Java虚拟机的同学应该比较熟悉这两个东东~垃圾回收机制也是围绕这里展开的,感兴趣的同学自己挖掘去噢~~

缓存

如何读取超过2G的大文件,通过Buffer解决。Node.js 官方建议,能用Buffer的话,尽量用Buffer。Buffer相对与字符串可以大幅度提高性能。

  • 超过8KB Buffer 的内存是在C++ 层面提供的(看到笔试经常有这个)

缓存是比较底层的应用,具体可以参考:

官方API

浅析nodejs的buffer类

Node.js 的 Buffer 那些你可能不知道的用法

web开发

一般来说,Node.js最大应用场景莫过于web开发了

  • 认识请求头(Request Headers)
    • User-Agent,基于这个可以分析客户端版本,系统信息,很多系统识别这个判断是否为爬虫,当然这只是很低级的
    • Referer,请求来源,一般可以根据这个防盗链,知道这个原理后,还可以反反盗链噢
    • Content-Type, 对于表单默认application/x-www-form-urlencoded,然而在做小程序开发的过程中,微信官方content-type 默认是 ‘application/json’,小小的tip里面写着,不在正文里面。当时一直以为我写错了,导致一直都是使用GET方式请求服务器,感觉这坑挺大的。Google 的 AngularJS 中的 Ajax 功能,默认也是提交 JSON 字符串。另外如果是上传文件,需要使用Content-Type指示文件的类型
    • 还有更多自行研究
  • 请求体(Request Body)
    • 有好几种格式:和Request Headers 里面的Content-Type一一对应
      1. application/json
      2. application/x-www-form-urlencoded
  • 认识响应头(Response Headers)
    • Cache- Control,缓存策略,好很多种指令。其中我觉得比较重要的是“max-age”,指令指定从请求的时间开始,允许获取的响应被重用的最长时间(单位:秒)。例如,“max-age=600”表示可在接下来的 10分钟请求同一个网址,都直接使用缓存,不在向服务器发生任何请求。使用这个方法可以降低服务器压力,当然延迟也会随之产生的,我在做小程序开发的过程中,一些几乎不变的数据,我就是响应max-age=86400的,也就是24小时。

    缓存并重用之前获取的资源的能力是性能优化的一个关键方面。(难得的谷歌中文技术文档)

  • 状态码(Status Code)
    • 200、301、302、500、、403、404这些极度常见我就不说了
    • 304: Not Modified(未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。 然后客户端会读取对应的本地缓存资源。

认识这些请求后,将有利于大幅度提高网站性能,还节省客户端流量

  • 所以开发过程中要对这些请求报头有所理解,遇到坑就会明白了,我遇过不少。

  • 数据处理

    • 查询字符串:Node提供querystring模块处理

      var query = url.parse(url.parse(req.url).query) ;//查询字符串就以json对象形式存入query了

  • 模板技术原理

  • 几种常见的漏洞与防范方法

  • 实际开发使用

测试与持续集成

企业级node

一定要知道的package

lodash

underscore

node.js 不得不去看的一些网站


Similar Posts

Comments