学习Node.js

Node.js入门经典读书笔记

Node.js是事件驱动的服务器端JavaScript环境, 以下简称Node

  • 使用JS操纵浏览器中的Web页面并与之交互, 成为客户端的JS
  • 服务器端JS发生在把页面发送给浏览器之前的服务器端

#1. 安装Node

主页 : http://nodejs.org下载响应平台的版本配置安装

ubuntu上可以使用类似sudo apt-get install nodejs进行安装

验证安装是否成功, 进入Terminal输入以下命令:

1
2
node -v //查看node版本号
npm -v //查看npm的版本号(Node Package Manager)
  • npm类似于Python中的包管理器pip, 使用npm安装模块,使用下面命令

npm install module_name #安装模块(本地安装), -g(全局安装)
npm search key1 key2 #关键词搜索模块, 多个关键词用空格隔开
npm docs module_name #查看模块文档

  • 在程序中使用模块, 必须下载, 然后再源码中进行模块请求
1
2
3
4
var module = require('module') //一般将模块赋予一个变量
安装coffee-script
coffee-script@1.8.0 /usr/local/lib/node_modules/coffee-script

##1.1. 使用package.json安装模块

创建package.json文件, 并加入以下内容 :

1
2
3
4
5
6
7
{
"name" : "project_name",
"version" : "0.0.1",
"dependencies" : {
"module_name" : "version"
}
}

#2. Node回调机制

1
2
3
4
5
6
7
8
//Node.js使用filesystem模块从磁盘读取文件内容
var fs = requires('fs');
fs.readFile('somefile.txt', 'utf8', function(err, data)
{
if(err)
throw err;
console.log(data);
});

发生的事情 :

  1. fs(filesystem)模块被请求, 以便在脚本中使用
  2. 将文件系统上的文件路径作为第一个参数提供给fs.readFile方法
  3. 第二个参数标识文件的编码
  4. 将回调函数作为第三参数提供给fs.readFile方法
  5. 回调函数第一个参数err, 用于保存在读取文件时返回的错误
  6. 第二个参数data, 用于保存读取文件所返回的数据
  7. 如果err为真, 则会抛出异常
  8. 如果err为假, 则来自文件的数据可以使用

回调是实现网络编程的关键方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var fs = require('fs'), http = require('http');
http.get({host : 'baidu.com'}, function(res)
{
console.log("got a response from baidu.com");
}).on('error', function(e)
{
console.log("there was an error from baidu.com");
});
fs.readFile('ex_one.js', 'utf8', function(err, data)
{
if (err) {
throw err;
};
console.log('ex_one.js read!');
});
  • 获取www.baidu.com的主页内容
  • 地区ex_one.js文件的内容
  • 对于两者的返回时间是不可预测的, 回调是负责解决不可预测性的方法, 也是处理并发的高效方法

##2.1. 同步和异步代码

  • 同步的代码意味着每次执行一个操作, 在一个操作完成前, 代码的执行会被阻塞
  • Node.js则是异步的调用回调(非阻塞)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var http = require('http')
function fetchPage () {
console.log('fetching page');
http.get({ host : 'trafficjamapp.herokuapp.com', path : '/?delay=2000'},
function(res)
{
console.log('data returned from requesting page');
}).on('error', function(e){
console.log("There was an error " + e);
});
}
function fetchApi () {
console.log('fetching api');
http.get({ host : 'trafficjamapp.herokuapp.com', path : '/?delay=2000'},
function(res){
console.log('data returned from the api');
}).on('error', function(e)
{
console.log("There was an error" + e);
});
}
fetchPage();
fetchApi();

运行结果 :
fetching page
fetching api
data returned from requesting page
data returned from the api

事件循环是的系统可以将回调函数保存起来, 而后当事件将来发生时再运行, 因为回调函数的执行被推迟到事情发生之后, 于是无需停止执行, 控制流可以返回到Node运行时的环境, 从来让其他事情发生. 核心思想:将代码围绕着时间来架构而不是按照期望的输入顺序来执行

为确保高性能需要遵循 :

  • 函数必须快速返回
  • 函数不得阻塞
  • 长时间运行的操作必须移到另一个进程中

#3. HTTP

HTTP头部发送的是附加的信息, 包括内容类型, 服务器发送响应的时间以及HTTP状态码

HTTP服务器

1
2
3
4
5
6
7
8
var http = require('http')//请http模块, 并赋予一个变量
http.createServer(function (req, res) //使用http.createServer创建一个新的Web服务对象
{
res.writeHead(200, {'Content-Type' : 'text/plain'}); //给服务器增加头部
res.end('Hello World\n'); //响应请求, 关闭连接
}
).listen(8000, "127.0.0.1");//标识可以使用127.0.0.1:8000来访问服务器
console.log('Server running at http://127.0.0.1:8000/'); //脚本将服务器的访问位置记录到控制台

##3.1. 查看HTTP头部

  • 通过一个python小程序可以查看服务器响应的头部
  • 使用Chrome浏览器可以使用HTTP Headers扩展程序, 同样可以查看HTTP头部
1
2
3
4
//使用OSX系统终端查看
brew install curl #安装curl
curl #查看是否安装成功, 若成功, 输入命令会显示curl: try 'curl --help' or 'curl --manual' for more information
curl -I 127.0.0.1:8000 #查看头部, 需要打开node服务器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from urllib2 import Request, urlopen, URLError, HTTPError
old_url = 'http://127.0.0.1:8000'
req = Request(old_url)
response = urlopen(req)
print 'Info():'
print response.info()
#输出结果
Info():
Content-Type: text/plain
Date: Sun, 02 Nov 2014 06:11:45 GMT
Connection: close
Transfer-Encoding: chunked

##3.2. Node.js中的重定向

1
2
3
4
5
6
7
8
9
10
11
12
var http = require('http');
http.createServer(function(req, res)
{
//重定向状态码为301
res.writeHead(301,
{
'Location' : 'http://andrewliu.tk/'
});
res.end();
}).listen(8000, "127.0.0.1");
console.log('Server runing at http://127.0.0.1:8000');

##3.3.响应不同的请求

路由指的是应用程序要响应的请求(资源)

1
2
3
4
5
6
var url = require('url');//请求url模块
var requestURL = 'http://andrewliu.tk'; //请求的URL
console.log(url.parse(requestURL).hostname); //URL的主机名
console.log(url.parse(requestURL).port);//端口号
console.log(url.parse(requestURL).pathname);//路径名

响应不同的请求需要不同的路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
var http = require('http'), url = require('url');
http.createServer(function(req, res)
{
var pathname = url.parse(req.url).pathname;
if(pathname === '/') //路径为127.0.0.1:3000
{
res.writeHead(200,
{
'Content-Type' : 'text/plain'
});
res.end('Home Page\n')
}
else if(pathname === '/about')//路径为127.0.0.1:3000/about
{
res.writeHead(200,
{
'Content-Type' : 'text/plain'
});
res.end('About Me\n')
}
else if(pathname === '/redirect')//路径为127.0.0.1:3000/redirect
{
res.writeHead(301,
{
'Location' : '/'
});
res.end();
}
else
{
res.writeHead(404,
{
'Content-Type' : 'text/plain'
});
res.end('Page not Found\n')
}
}).listen(3000, "127.0.0.1");
console.log('Server running at http://127.0.0.1:3000');

##3.4. Node.js客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//通过http欢呼段来查看Web服务器的状态
var http = require('http');
var options = {
host : 'andrewliu.tk',
port : 80,
path : '/'
};
http.get(options, function(res)
{
if(res.statusCode === 200)
{
console.log("The site is up!");
}
else
{
console.log("The site is down!");
}
}).on('error', function(e){
console.log('There was an error :' + e.message);

#4. Express框架(Web框架)

安装express

npm install -g express
npm install -g express-generator
express first_express && cd first_express 创建并打开express站点框架,命名为first_express
npm install 通过package.json安装依赖模块
npm start启动站点

框架结构 :

  • app.js 启动应用程序的应用程序文件夹(包含应用程序配置)
  • node_modules 保存安装的Node模块
  • package.json 提供应用程序信息(运行需要依赖模块)
  • public 公共文件夹
  • routes 定义程序应该响应的页面
  • views 定义应用程序的布局

##4.1. 介绍Jade

  • Jade是基于缩进的模板引擎(缩进定义HTML层次结构)
  • Jade比HTML简介
  • Jade无需使用标记, 编译模板的时候会自动加入<>字符
  • Jade无需关闭HTML标记, Jade生成HTML的时候会为我们关闭标记
标记 Jade HTML
普通标记 html <html></html>
id section#wrapper <section id = "wrapper"></section>
p.highlight <p class = "highlight"></p>
类和id p#wrapper.class_name <p id = "wrapper" class = "class_name"></p>
多个类 p.classone.classtwo <p class = "classone classtwo"></p>
1
2
3
4
5
<!--缩进 Jade-->
p
span
<!---编译后HTML-->
<p><span></span></p>
1
2
3
4
- var foo = Node;
p I want to learn #{foo}! // #{变量} 告诉Jade用变量替换字符窜foo
//编译后的记过
<p>I want to learn Node!</p>

Jade简单语法范例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
extends layout
block content
h1= title
p Welcome to #{title}
//变量
- var name = "Andrew_liu"
p This is my first Test for #{name}!
//循环
- var users =['Liu', 'Bin', 'Andrew', 'Dinosaur']
- each user in users
p= user
//对象迭代
- obj = {first : 'LIU', last : 'BIN'}
- each val, key in obj
li #{key} : #{val}
//条件
- raining = true
- if (raining)
p It is raining , Take Something!
- else
p No rain, Take the bike!
//内连JavaScript
//include
html
body
p Hello World
h1 Hello World
h1 Jade inlcude example
include includes/footer
//Minix,常用代码的封装
mixin users(users)
ul
each user in users
li= user
- users = ['liu', 'bin', 'good']
mixin users(users)