Node.js是什么?
Node.js是建立在谷歌Chrome的JavaScript引擎(V8引擎)的Web应用程序框架。 它的最新版本是:v0.12.7(在编写本教程时的版本)。Node.js在官方网站的定义文件内容如下:
Node.js® is a platform built onChrome's JavaScript runtimefor easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.
Node.js自带运行时环境可在Javascript脚本的基础上可以解释和执行(这类似于JVM的Java字节码)。这个运行时允许在浏览器以外的任何机器上执行JavaScript代码。由于这种运行时在Node.js上,所以JavaScript现在可以在服务器上并执行。
Node.js还提供了各种丰富的JavaScript模块库,它极大简化了使用Node.js来扩展Web应用程序的研究与开发。
Node.js = 运行环境+ JavaScript库
Node.js特性
Node.js库的异步和事件驱动的API全部都是异步就是非阻塞。它主要是指基于Node.js的服务器不会等待API返回的数据。服务器移动到下一个API调用,Node.js发生的事件通知机制后有助于服务器获得从之前的API调用的响应。
非常快的内置谷歌Chrome的V8 JavaScript引擎,Node.js库代码执行是非常快的。
单线程但高度可扩展 - Node.js使用具有循环事件单线程模型。事件机制有助于服务器在一个非阻塞的方式响应并使得服务器高度可扩展,而不是创建线程限制来处理请求的传统服务器。Node.js使用单线程的程序,但可以提供比传统的服务器(比如Apache HTTP服务器)的请求服务数量要大得多。
没有缓冲 - Node.js的应用从来不使用缓冲任何数据。这些应用只是输出数据在块中。
许可证协议 - Node.js 在MIT 协议下发布
都有谁在使用Node.js?
以下是包含正在使用node.js的项目,应用和公司,一个详尽的清单请点击 github维基链接查看,这些清单里包括:eBay, General Electric, GoDaddy, Microsoft, PayPal, Uber, Wikipins, Yahoo!, Yammer 并越来越多加入继续扩大这个列表:使用NodeJS的项目, 应用和公司
概念
在哪里可以使用Node.js?
以下是Node.js证明自己完美的技术的合作伙伴的领域。
I/O 绑定应用程序
数据流应用
数据密集型实时应用(DIRT)
JSON API的应用程序
单页面应用
在哪些地方不要使用Node.js?
不建议使用Node.js的就是针对CPU密集型应用。
Node.js - 环境安装配置
如果愿意安装设置Node.js环境,需要计算机上提供以下两个软件:
一、文本编辑器
二、Node.js二进制安装包
文本编辑器
这将用来编写程序代码。 一些编辑器包括:Windows记事本,OS Edit命令,Brief, Epsilon, EMACS和VIM或vi。
文本编辑器的名称和版本的在不同的操作系统可能不太相同。例如,记事本可用在Windows,VIM或vi可以在Windows以及Linux或UNIX上使用。
编辑器创建的文件称为源文件并包含程序的源代码。 对于Node.js的程序的源文件名通常命名扩展是 ".js".
在开始编程之前,请确保文本编辑器可用,并且有足够的经验来写计算机程序,将其保存在一个文件,如:helloworld.js,编译并执行。
Node.js 运行时
编写源文件中的源代码只需知道了解JavaScript。Node.js解释器将用于解释和执行JavaScript代码。
Node.js的发行版以二进制安装在SunOS,Linux,Mac OS X和Windows的32位(386)和64位(AMD64)的x86处理器架构操作系统。
以下部分将指导如何将Node.js的二进制分发版安装在各种操作系统上。
下载Node.js的归档文件
下载最新版本Node.js的安装归档文件在:Node.js 下载. 在写这篇教程的时候,下载的是node-v0.12.7-x64.msi并复制到“桌面”。
OS Archive name
Windowsnode-v0.12.7-x64.msi
Linux node-v0.12.7-linux-x86.tar.gz
Mac node-v0.12.7-darwin-x86.tar.gz
SunOS node-v0.12.7-sunos-x86.tar.gz
在UNIX/Linux/Mac OS X和SunOS上安装(可选)
解压缩下载归档文件到 /usr/local, 创建一个NodeJs树 /usr/local/nodejs. 例如:
tar -C /usr/local -xzf node-v0.12.0-linux-x86.tar.gz
添加 /usr/local/nodejs 到PATH环境变量。
OS 输出
Linux export PATH=$PATH:/usr/local/nodejs
Mac export PATH=$PATH:/usr/local/nodejs
FreeBSD export PATH=$PATH:/usr/local/nodejs
在Windows上安装Node.js(本教程中使用)
使用MSI文件,并按照提示安装node.js,默认情况下,安装程序将 Node.js 发行到 C:\Program Files\nodejs. 但这里我们需要修改安装路径到:D:\yiibai_worksp\nodejs,并将 D:\yiibai_worksp\nodejs 目录添加到Window系统的PATH环境变量中。重新启动打开命令提示符,以使更改生效。
Node.js - 第一个应用程序
在使用 Node.js 创建 Hello World ! 应用程序之前, 让我们看看Node.js的应用程序的组成部分。Node.js应用程序由以下三个重要部分组成:
导入所需模块: 使用require指令来加载javascript模块
创建一个服务器: 服务器这将听监听在Apache HTTP服务器客户端的请求。
读取请求并返回响应: 在前面的步骤中创建的服务器将响应读取由客户机发出的HTTP请求(可以是一个浏览器或控制台)并返回响应。
创建Node.js应用
步骤 1:导入所需的包
使用require指令来加载 HTTP 模块。
varhttp=require("http")
步骤 2:使用http.createServer方法创建HTTP服务器。通过参数函数请求并响应。编写示例实现返回“Hello World”。服务器在8081端口监听。
http.createServer(function (request, response) {
// HTTP Status: 200 : OK
// Content Type: text/plain
response.writeHead(200, {'Content-Type': 'text/plain'});
// send the response body as "Hello World"
response.end('Hello World\n');
}).listen(8081);
// console will print the message
console.log('Server running at http://127.0.0.1:8081/');
步骤 3:创建一个 js 文件在 helloworld.js 在D:\>yiibai_worksp.
File: helloworld.js
var http = require("http")
http.createServer(function (request, response) {
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end('Hello World\n');
}).listen(8081);
console.log('Server running at http://127.0.0.1:8081/');
现在运行 helloworld.js 看到结果:
D:\yiibai_worksp\nodejs>node helloworld.js
验证输出,服务器应用已经启动!
Server running at http://127.0.0.1:8081/
向Node.js服务器发出请求
Node.js - REPL
REPL代表读取评估和演示打印循环,它就像 Window 下的控制台的计算机环境,或 Unix/Linux 系统的 Shell命令输入响应输出。 Node.js或Node 捆绑了一个REPL环境。可执行以下任务。
读取- 读取用户的输入,解析输入的JavaScript数据结构并存储在内存
计算- 采取并评估计算数据结构
打印- 打印结果
循环- 循环上面的命令,直到用户按Ctrl-C两次终止
Node 的REPL 与 Node.js 的实验代码非常有用,用于调试JavaScript代码。
特点
REPL可以通过简单地在shell/控制台运行node不带任何参数来启动。
D:\yiibai_worksp\nodejs> node
可以看到REPL 命令提示符:
D:\yiibai_worksp\nodejs> node
>
简单的表达式
让我们尝试在REPL命令提示符下执行简单的数学运算:
D:\yiibai_worksp\nodejs>node
> 1 + 3
4
> 1 + ( 2 * 3 ) - 4
3
>
使用变量
使用变量储存值后并打印。如果不使用var关键字,那么值存储在变量并打印。而如果使用var关键字存储值,那么不会打印。稍后,可以使用这两个变量。使用console.log()打印来任何东西
D:\yiibai_worksp\nodejs> node
> x = 10
10
> var y = 10
undefined
> x + y
20
> console.log("Hello World")
Hello Workd
undefined
多行表达
Node REPL支持类似于JavaScript的多表达。请参阅下列do-while循环:
D:\yiibai_worksp\nodejs> node
> var x = 0
undefined
> do {
... x++;
... console.log("x: " + x);
... } while ( x < 5 );
x: 1
x: 2
x: 3
x: 4
x: 5
undefined
>
... 当按下进入自动打开来后括号。Node自动检查表达式的连续性。
下划线变量
使用_得到最后的结果。
D:\yiibai_worksp\nodejs> node
> var x = 10
undefined
> var y = 20
undefined
> x + y
30
> var sum = _
undefined
> console.log(sum)
30
undefined
>
REPL 命令
ctrl + c - 终止当前命令
ctrl + c twice - 终止 Node REPL
ctrl + d - 终止 Node REPL
Up/Down Keys - 查看命令历史记录和修改以前的命令
tab Keys - 当前命令列表
.help - 列出所有命令
.break - 退出多行表达
.clear - 从多行表达式退出
.save - 当前 Node REPL会话保存到一个文件
.load - 加载文件的内容到当前Node REPL会话
D:\yiibai_worksp\nodejs> node
> var x = 10
undefined
> var y = 20
undefined
> x + y
30
> var sum = _
undefined
> console.log(sum)
30
undefined
> .save test.js
Session saved to:test.js
> .load test.js
> var x = 10
undefined
> var y = 20
undefined
> x + y
30
> var sum = _
undefined
> console.log(sum)
30
undefined
>
Node.js - npm
npm 表示节点程序包管理器。npm 提供以下两个主要功能:
Node.js包/模块的在线软件仓库,可通过搜索search.nodejs.org
命令行实用程序安装包,作为Node.js版本管理和依赖包管理。
Node.js v0.6.3版本后才开始捆绑 npm 安装。为了验证,打开控制台,然后输入以下命令并查看结果:
D:\yiibai_worksp\nodejs>npm --version
2.11.3
全局VS本地安装
默认情况下,NPM安装在任何依赖性的本地模式。在这里,本地模式指的是包在安装目录node_modules,位于Node应用的文件夹中。本地部署的包都可以通过require() 访问 。
全局安装的软件包/依赖存储在<用户目录>/npm目录。 这种依赖关系可以在命令行中使用Node.js的(命令行界面)任何功能,但不能使用require()在Node直接应用导入。
我们来开始安装明确,使用本地来安装一个流行的Web框架。
D:\yiibai_worksp\nodejs>npm install express
express@4.11.2 node_modules\express
|-- merge-descriptors@0.0.2
|-- utils-merge@1.0.0
|-- methods@1.1.1
|-- escape-html@1.0.1
|-- fresh@0.2.4
|-- cookie@0.1.2
|-- range-parser@1.0.2
|-- media-typer@0.3.0
|-- cookie-signature@1.0.5
|-- vary@1.0.0
|-- finalhandler@0.3.3
|-- parseurl@1.3.0
|-- serve-static@1.8.1
|-- content-disposition@0.5.0
|-- path-to-regexp@0.1.3
|-- depd@1.0.0
|-- qs@2.3.3
|-- debug@2.1.1 (ms@0.6.2)
|-- send@0.11.1 (destroy@1.0.3, ms@0.7.0, mime@1.2.11)
|-- on-finished@2.2.0 (ee-first@1.1.0)
|-- type-is@1.5.7 (mime-types@2.0.9)
|-- accepts@1.2.3 (negotiator@0.5.0, mime-types@2.0.9)
|-- etag@1.5.1 (crc@3.2.1)
|-- proxy-addr@1.0.6 (forwarded@0.1.0, ipaddr.js@0.1.8)
一旦NPM完成下载,可以通过查看 D:\yiibai_worksp\nodejs\node_modules 的内容验证,或键入以下命令:
D:\yiibai_worksp\nodejs> npm ls
D:\yiibai_worksp\nodejs
|-- express@4.11.2
|-- accepts@1.2.3
| |-- mime-types@2.0.9
| | |-- mime-db@1.7.0
| |-- negotiator@0.5.0
|-- content-disposition@0.5.0
|-- cookie@0.1.2
|-- cookie-signature@1.0.5
|-- debug@2.1.1
| |-- ms@0.6.2
|-- depd@1.0.0
|-- escape-html@1.0.1
|-- etag@1.5.1
| |-- crc@3.2.1
|-- finalhandler@0.3.3
|-- fresh@0.2.4
|-- media-typer@0.3.0
|-- merge-descriptors@0.0.2
|-- methods@1.1.1
|-- on-finished@2.2.0
| |-- ee-first@1.1.0
|-- parseurl@1.3.0
|-- path-to-regexp@0.1.3
|-- proxy-addr@1.0.6
| |-- forwarded@0.1.0
| |-- ipaddr.js@0.1.8
|-- qs@2.3.3
|-- range-parser@1.0.2
|-- send@0.11.1
| |-- destroy@1.0.3
| |-- mime@1.2.11
| |-- ms@0.7.0
|-- serve-static@1.8.1
|-- type-is@1.5.7
| |-- mime-types@2.0.9
| |-- mime-db@1.7.0
|-- utils-merge@1.0.0
|-- vary@1.0.0
上面列出的内容很长,这里省略了一部分。
现在,让我们尝试安装明确,使用全局安装流行Web框架。
D:\yiibai_worksp\nodjs> npm install express - g
一旦NPM完成下载,可以通过查看<用户目录>/nmp/node_modules中的内容来验证。或输入以下命令:
D:\yiibai_worksp\nodejs> npm ls -g
以上可能会遇网络问题无法安装,需要翻墙。
安装模块
安装模块很简单,只要键入以下命令。
D:\yiibai_worksp\nodejs> npm install express
现在,可以在 js 文件中使用它,如下:
varexpress=require('express');
package.json 包
package.json是存在于任何Node应用程序/模块的根目录,并用于定义一个包的属性。 让我们打开 package.json express包在 D:\yiibai_worksp\nodejs\node_modules\express\
{
"name": "express",
"description": "Fast, unopinionated, minimalist web framework",
"version": "4.11.2",
"author": {
"name": "TJ Holowaychuk",
"email": "tj@vision-media.ca"
},
"contributors": [
{
"name": "Aaron Heckmann",
"email": "aaron.heckmann+github@gmail.com"
},
{
"name": "Ciaran Jessup",
"email": "ciaranj@gmail.com"
},
{
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
},
{
"name": "Guillermo Rauch",
"email": "rauchg@gmail.com"
},
{
"name": "Jonathan Ong",
"email": "me@jongleberry.com"
},
{
"name": "Roman Shtylman",
"email": "shtylman+expressjs@gmail.com"
},
{
"name": "Young Jae Sim",
"email": "hanul@hanul.me"
}
],
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/strongloop/express"
},
"homepage": "http://expressjs.com/",
"keywords": [
"express",
"framework",
"sinatra",
"web",
"rest",
"restful",
"router",
"app",
"api"
],
"dependencies": {
"accepts": "~1.2.3",
"content-disposition": "0.5.0",
"cookie-signature": "1.0.5",
"debug": "~2.1.1",
"depd": "~1.0.0",
"escape-html": "1.0.1",
"etag": "~1.5.1",
"finalhandler": "0.3.3",
"fresh": "0.2.4",
"media-typer": "0.3.0",
"methods": "~1.1.1",
"on-finished": "~2.2.0",
"parseurl": "~1.3.0",
"path-to-regexp": "0.1.3",
"proxy-addr": "~1.0.6",
"qs": "2.3.3",
"range-parser": "~1.0.2",
"send": "0.11.1",
"serve-static": "~1.8.1",
"type-is": "~1.5.6",
"vary": "~1.0.0",
"cookie": "0.1.2",
"merge-descriptors": "0.0.2",
"utils-merge": "1.0.0"
},
"devDependencies": {
"after": "0.8.1",
"ejs": "2.1.4",
"istanbul": "0.3.5",
"marked": "0.3.3",
"mocha": "~2.1.0",
"should": "~4.6.2",
"supertest": "~0.15.0",
"hjs": "~0.0.6",
"body-parser": "~1.11.0",
"connect-redis": "~2.2.0",
"cookie-parser": "~1.3.3",
"express-session": "~1.10.2",
"jade": "~1.9.1",
"method-override": "~2.3.1",
"morgan": "~1.5.1",
"multiparty": "~4.1.1",
"vhost": "~3.0.0"
},
"engines": {
"node": ">= 0.10.0"
},
"files": [
"LICENSE",
"History.md",
"Readme.md",
"index.js",
"lib/"
],
"scripts": {
"test": "mocha --require test/support/env --reporter spec --bail --check-leaks test/ test/acceptance/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks test/ test/acceptance/",
"test-tap": "mocha --require test/support/env --reporter tap --check-leaks test/ test/acceptance/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks test/ test/acceptance/"
},
"gitHead": "63ab25579bda70b4927a179b580a9c580b6c7ada",
"bugs": {
"url": "https://github.com/strongloop/express/issues"
},
"_id": "express@4.11.2",
"_shasum": "8df3d5a9ac848585f00a0777601823faecd3b148",
"_from": "express@*",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "tjholowaychuk",
"email": "tj@vision-media.ca"
},
{
"name": "jongleberry",
"email": "jonathanrichardong@gmail.com"
},
{
"name": "shtylman",
"email": "shtylman@gmail.com"
},
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
{
"name": "aredridel",
"email": "aredridel@nbtsc.org"
},
{
"name": "strongloop",
"email": "callback@strongloop.com"
},
{
"name": "rfeng",
"email": "enjoyjava@gmail.com"
}
],
"dist": {
"shasum": "8df3d5a9ac848585f00a0777601823faecd3b148",
"tarball": "http://registry.npmjs.org/express/-/express-4.11.2.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/express/-/express-4.11.2.tgz",
"readme": "ERROR: No README data found!"
}
Package.json 属性
name - 包的名称
version- 包的版本
description- 包的描述
homepage- 包的网站主页
author- 包的作者
contributors- 包的贡献者的名称列表
dependencies- 依赖性列表。npm自动安装所有在node_module文件夹中的包提到的依赖关系。
repository- 包的存储库类型和URL
main- 包的入口点
keywords- 关键字
卸载模块
请使用以下命令卸载模块。
D:\yiibai_worksp\nodejs> npm uninstall express
当npm卸载的软件包,可以通过查看<用户目录>/npm/node_modules 的内容验证。或键入以下命令:
D:\yiibai_worksp\nodejs> npm ls
更新模块
更新的package.json并更改其版本依赖关系进行更新,运行以下命令。
D:\yiibai_worksp\nodejs> npm update
搜索模块
使用npm搜索包名。
D:\yiibai_worksp\nodejs>npm search express
创建一个模块
创建模块需要要生成package.json。让我们使用 npm 产生 package.json。
D:\yiibai_worksp\nodejs> npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sane defaults.
See 'npm help json' for definitive documentation on these fields
and exactly what they do.
Use 'npm install <pkg> --save' afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
name: (Nodejs_WorkSpace)
一旦的 package.json 产生。使用一个有效的电子邮件地址在npm库网站上注册自己,使用如面的命令。
D:\yiibai_worksp\nodejs> npm adduser
现在,是时候来发布模块了:
D:\yiibai_worksp\nodejs> npm publish
Node.js - 回调概念
什么是回调?
回调是一种异步相当于一个函数。回调函数被调用在完成既定任务。Node大量使用了回调。Node所有的API写的都是支持回调的这样一种方式。例如,一个函数读取一个文件可能开始读取文件,并立即返回控制到执行环境 使得下一个指令可以马上被执行。一旦文件 I/O 完成,它会调用回调函数,同时传递回调函数,该文件作为参数的内容。因此不会有堵塞或等待文件I/O。这使得Node.js高度可扩展,因此可以处理大量的请求,而无需等待任何函数来返回结果。
阻塞代码示例
创建一个 txt 文件:test.txt 在 D:\>yiibai_worksp\nodejs目录
Yiibai.Com
创建一个名为test.js 的js文件在 D:\>yiibai_worksp\nodejs
varfs=require("fs");vardata=fs.readFileSync('test.txt');console.log(data.toString());console.log("Program Ended");
现在运行 test.js 看到的结果:
D:\yiibai_worksp\nodejs>node test.js
验证输出结果:
Yiibai.com
Program Ended
非阻塞代码示例
创建一个 txt 文件:test.txt 在D:\>yiibai_worksp\nodejs目录
Yiibai.Com
更新 test.js 的内容在目录D:\>yiibai_worksp\nodejs
varfs=require("fs");fs.readFile('test.txt',function(err,data){if(err)returnconsole.error(err);console.log(data.toString());});console.log("Program Ended");
现在运行 test.js 看到的结果:
D:\yiibai_worksp\nodejs> node test.js
验证输出
Program Ended
Yiibai.Com
事件循环概述
Node JS是单线程应用程序,但它通过事件和回调的概念,支持并发。NodeJS的每一个API都是异步的,作为一个单独的线程,它使用异步函数调用来维护并发。Node使用观察者模式。Node线程保持一个事件循环,每当任何任务完成后得到结果,它触发通知事件侦听函数来执行相应的事件。
事件驱动编程
Node.js使用大量事件,这也是为什么Node.js相对于其他类似技术比较快的原因之一。当Node启动其服务器,就可以简单地初始化其变量,声明函数,然后等待事件的发生。
虽然事件似乎类似于回调。不同之处在于当回调函数被调用异步函数返回结果,其中的事件处理工作在观察者模式。监听事件函数作为观察者。每当一个事件被解雇,其监听函数开始执行。Node.js有多个内置的事件。 主要扮演者是 EventEmitter,可使用以下语法导入。
//import events module
var events = require('events');
//create an eventEmitter object
var eventEmitter = new events.EventEmitter();
示例
创建一个 js 文件名为 test.js 的文件在D:\>yiibai_worksp\nodejs
File: test.js
//import events module
var events = require('events');
//create an eventEmitter object
var eventEmitter = new events.EventEmitter();
//create a function connected which is to be executed
//when 'connection' event occurs
var connected = function connected() {
console.log('connection succesful.');
// fire the data_received event
eventEmitter.emit('data_received.');
}
// bind the connection event with the connected function
eventEmitter.on('connection', connected);
// bind the data_received event with the anonymous function
eventEmitter.on('data_received', function(){
console.log('data received succesfully.');
});
// fire the connection event
eventEmitter.emit('connection');
console.log("Program Ended.");
现在运行test.js看到的结果:
D:\yiibai_worksp\nodejs> node test.js
验证输出。服务器已经启动
connection succesful.
data received succesfully.
Program Ended.