学习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 17 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)