学习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); });
|
发生的事情 :
- fs(
filesystem)模块被请求, 以便在脚本中使用
- 将文件系统上的文件路径作为第一个参数提供给fs.readFile方法
- 第二个参数标识文件的编码
- 将回调函数作为第三参数提供给fs.readFile方法
- 回调函数第一个参数err, 用于保存在读取文件时返回的错误
- 第二个参数data, 用于保存读取文件所返回的数据
- 如果err为真, 则会抛出异常
- 如果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)
|