node战斗课程一
写在前面:
大家期待已久的node.js课程终于和大家见面。
本次课程的目的:是希望通过本次的课程学习,大家可以熟悉node.js,知道怎么基础使用node.js,能看的懂node.js的代码。
我会以一个实时的聊天项目作为课程的核心切入点,带大家透彻的了解这个项目的组成和运行方式。为了方便大家容易看的懂,我贴心的用了jquery作为客户端的前端框架。
本次课程的流程:node.js的基础 -》 项目依赖的技术像socket.io 的讲解 -》聊天项目的讲解 -》(动手部分)更改这个项目的样式和增加功能后发到线上环境,让这个成为我们的专用的交流工具。
node.js的基础大概需要两讲,技术依赖可能不需要一讲,但可能会添加些其他的东西,项目的讲解和修改大概需要一讲。
本次课程参考了书籍:node.js实战(第一季),node.js实战(第二季),深入浅出node.js,前端面试手册,以及廖雪峰官方网站node.js部分和菜鸟课程系列等。
课程一关键词:node.js历史,模块化,基本模块(部分)
node.js历史
在讲一个技术的时候必要谈其历史,因为我们可以从其起源的时机以及发展趋势推测其是否有着被学习的必要。
Node.js是什么? 现在Node还很年轻(它的首次亮相是在2009年),却非常流行。它在Github受关注项目排行榜上位列第二
,在Google小组和IRC频道中都有很多追随者,并且社区同仁们在NPM包管理网站上发布的模块多达15 000 多个。所有这些都足以表明这个平台的强大吸引力。这是现状不是历史,谈及历史必须要先谈及当年的浏览器大战。
在Netscape设计出JavaScript后的短短几个月,JavaScript事实上已经是前端开发的唯一标准。
后来,微软通过IE击败了Netscape后一统桌面,结果几年时间,浏览器毫无进步。(2001年推出的古老的IE 6到今天仍然有人在使用!)
没有竞争就没有发展。微软认为IE6浏览器已经非常完善,几乎没有可改进之处,然后解散了IE6开发团队!而Google却认为支持现代Web应用的新一代浏览器才刚刚起步,尤其是浏览器负责运行JavaScript的引擎性能还可提升10倍。
上个世纪的90年代真的是群魔乱舞,百家争鸣,先是Mozilla借助已壮烈牺牲的Netscape遗产在2002年推出了Firefox浏览器,紧接着Apple于2003年在开源的KHTML浏览器的基础上推出了WebKit内核的Safari浏览器,不过仅限于Mac平台。
随后,Google也开始创建自家的浏览器。他们也看中了WebKit内核,于是基于WebKit内核推出了Chrome浏览器。
Chrome浏览器是跨Windows和Mac平台的,并且,Google认为要运行现代Web应用,浏览器必须有一个性能非常强劲的JavaScript引擎,于是Google自己开发了一个高性能JavaScript引擎,名字叫V8,以BSD许可证开源。
现代浏览器大战让微软的IE浏览器远远地落后了,因为他们解散了最有经验、战斗力最强的浏览器团队!回过头再追赶却发现,支持HTML5的WebKit已经成为手机端的标准了,IE浏览器从此与主流移动端设备绝缘。
浏览器大战和Node有何关系?
话说有个叫Ryan Dahl的老外(网上说是个死肥仔),他的工作是用C/C++写高性能Web服务。对于高性能,异步IO、事件驱动是基本原则,但是用C/C++写就太痛苦了。于是这位仁兄开始设想用高级语言开发Web服务。他评估了很多种高级语言,发现很多语言虽然同时提供了同步IO和异步IO,但是开发人员一旦用了同步IO,他们就再也懒得写异步IO了,所以,最终,Ryan瞄向了JavaScript。
因为JavaScript是单线程执行,根本不能进行同步IO操作,所以,JavaScript的这一“缺陷”导致了它只能使用异步IO。
选定了开发语言,还要有运行时引擎。这位仁兄曾考虑过自己写一个,不过明智地放弃了,因为V8就是开源的JavaScript引擎。让Google投资去优化V8,咱只负责改造一下拿来用,还不用付钱,这个买卖很划算。
于是在2009年,Ryan正式推出了基于JavaScript语言和V8引擎的开源Web服务器项目,命名为Node.js。虽然名字很土,但是,Node第一次把JavaScript带入到后端服务器开发,加上世界上已经有无数的JavaScript开发人员,所以Node一下子就火了起来。
在Node上运行的JavaScript相比其他后端开发语言有何优势?
最大的优势是借助JavaScript天生的事件驱动机制加V8高性能引擎,使编写高性能Web服务轻而易举。
其次,JavaScript语言本身是完善的函数式语言,在前端开发时,开发人员往往写得比较随意,让人感觉JavaScript就是个玩具语言。但是,在Node环境下,通过模块化的JavaScript代码,加上函数式编程,并且无需考虑浏览器兼容性问题,直接使用最新的ECMAScript 6标准,可以完全满足工程上的需求。Node用的虚拟机(V8)会紧跟ECMAScript标准。换句话说,在Node中如果想用新的JavaScript语言特性,不用等到所有浏览器都支持。
模块化
说到node.js必然会谈到模块,由于前人已经详细说过,我在这就大概提一下。
在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护。
为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。在Node环境中,一个.js文件就称之为一个模块(module)。
使用模块有什么好处?
最大的好处是大大提高了代码的可维护性。其次,编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。我们在编写程序的时候,也经常引用其他模块,包括Node内置的模块和来自第三方的模块。
使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中,因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。
具体举个例子:
比如我们编写了一个hello.js文件,这个hello.js文件就是一个模块,模块的名字就是文件名(去掉.js后缀),所以hello.js文件就是名为hello的模块。
var s = 'Hello';
function greet(name) {
console.log(s + ', ' + name + '!');
}
module.exports = greet;
函数**greet()**是我们在hello模块中定义的,你可能注意到最后一行是一个奇怪的赋值语句,它的意思是,把函数greet作为模块的输出暴露出去,这样其他模块就可以使用greet函数了。
问题是其他模块怎么使用hello模块的这个greet函数呢?我们再编写一个main.js文件,调用hello模块的greet函数:
// 引入hello模块:
var greet = require('./hello');
var s = 'Michael';
greet(s); // Hello, Michael!
注意到引入hello模块用Node提供的require函数。
说到require,又有些东西需要提:
require是Node中少数几个同步I/O操作之一。因为经常用到模块,并且一般都是在文件顶端引入,所以把require做成同步的有助于保持代码的整洁、有序,还能增强可读性。
但在程序中I/O密集的地方尽量不要用require。所有同步调用都会阻塞Node,直到调用完成才能做其他事情。比如你正在运行一个HTTP服务器,如果在每个进入的请求上都用了require,就会遇到性能问题。所以通常都只在程序最初加载时才使用require和其他同步操作。
关于模块化就带大家了解一下基础的用法回顾一下。
基础模块
在说基础模块之前,希望大家先有一个概念,Node.js是运行在服务区端的JavaScript环境,服务器程序和浏览器程序相比,最大的特点是没有浏览器的安全限制了,而且,服务器程序必须能接收网络请求,读写文件,处理二进制内容,所以,Node.js内置的常用模块就是为了实现基本的服务器功能。这些模块在浏览器环境中是无法被执行的,因为它们的底层代码是用C/C++在Node.js运行环境中实现的。
global
JavaScript有且仅有一个全局对象,在不同的环境,名称不同,在浏览器中,叫window对象。而在Node.js环境中,也有唯一的全局对象,但不叫window,而叫global,这个对象的属性和方法也和浏览器环境的window不同。
在《javaScript高级程序设计》一书中介绍了有关此部分内容: ECMAScript中的Global对象在某种意义上是作为一个终极的“兜底儿对象”定义的。换句话说,不属于任何其他对象的属性和方法,最终都是它属性和方法。事实上,没有全局变量和全局函数;所有在全局作用域中定义的属性和函数,都是Global对象的属性,诸如:isNaN(),isFinite(),pareInt()以及parseFloat()。
在浏览器中的window,实际上是 web API,归根还是global。用一句俗话来说:global 就是老祖宗!
process
process也是Node.js提供的一个对象,它代表当前Node.js进程。通过process对象可以拿到许多有用信息:
> process === global.process;
true
> process.version;
'v10.13.0'
> process.platform;
'darwin'
> process.arch;
'x64'
> process.cwd(); //返回当前工作目录
'/Users/gaozhiyuan'
javaScript程序是由事件驱动执行的单线程模型,Node.js也不例外。Node.js不断执行响应事件的JavaScript函数,直到没有任何响应事件的函数可以执行时,Node.js就退出了。
如果我们想要在下一次事件响应中执行代码,可以调用process.nextTick():
process.nextTick(function () {
console.log('nextTick callback!');
});
console.log('nextTick was set!');
结果大家应该都知道,这个例子很小,但是却把node.js的核心理念暴露了出来。
单线程
事件驱动
非阻塞
异步I/O
代码的执行顺序是由上而下,我用process.nextTick()代替数据交互说需要的时间,体现他的非租塞异步I/O。
具体看下面这样图: