鸟瞰Nodejs
2014-06-10 23:27 FuzhePan 阅读(1198) 评论(1) 编辑 收藏 举报一,基础。
1,Node的包管理器:npm; 安装node环境时会自动安装。
本地模式获取一个包:npm install [package_name]
此时包被安装到当前木的node_modules子目录下。
全局模式获取一个包;npm install -g [package_name]
全局模式安装的包不能直接通过require使用,但通过npm link命令可以在当前目录创建一个指向全局包的链接。比如,如果已经通过 npm install -g express 安装了 express, 这时在工程的目录下运行命令:
npm link express
./node_modules/express -> /usr/local/lib/node_modules/express
2,第一个程序。
创建helloworld.js文件,并写入:console.log("Hello World");
打开cmd,进入hellodworld.js所在目录,运行:node hellowrold.js
3,命令行工具node。
查看帮助信息:node --help
REPL模式:即时求值的环境,类似于浏览器的控制台,直接输入node。
4,建立Http服务器。
运行以下代码,然后浏览器打开 localhost:3000
//app.js
var http = require('http'); http.createServer(function(req, res) { res.writeHead(200, {'Content-Type': 'text/html'}); res.write('<h1>Node.js</h1>'); res.end('<p>Hello World</p>'); }).listen(3000); console.log("HTTP server is listening at port 3000.");
如果运行app.js后,再修改app.js并不会实时反映到浏览器端,必须退出重新运行。
如果想实时看到修改后的效果,可以采用supervisor。
使用方法:
安装supervisor: npm install -g supervisor
使用supervisor运行app.js: supervisor app.js
5,读取文件。
5.1异步读取文件:
//readfile.js
var fs = require('fs'); fs.readFile('file.txt', 'utf-8', function(err, data) { if (err) { console.error(err); } else { console.log(data); } }); console.log('end.');
可以看到,是通过回调函数实现异步。调用时只是将I/O请求发送给了操作系统,然后继续执行后面的代码,执行完成后进入事件循环监听事件。当fs接受到I/O请求完成的事件时,事件循环会主动调用回调函数。
5.2同步读取文件:
//readfilesync.js
var fs = require('fs'); var data = fs.readFileSync('file.txt', 'utf-8'); console.log(data); console.log('end.');
6,事件。
//event.js
var EventEmitter = require('events').EventEmitter; var event = new EventEmitter(); event.on('some_event', function() { console.log('some_event occured.'); }); setTimeout(function() { event.emit('some_event'); }, 1000);
7,node.js的事件循环机制。
node.js程序本身就是一堆事件的回调函数。程序的入口是事件循环第一个事件的回调函数。事件的回调函数在执行的过程中,可能会有异步请求或直接emit事件,执行完毕后再返回事件循环,事件循环会检查事件队列中的未处理事件,直到程序结束。
8,模块和包(Module 、Package)。
8.1创建并使用模块。
//module.js
var name; exports.setName = function(thyName) { name = thyName; }; exports.sayHello = function() { console.log('Hello ' + name); };
//getmodule.js
var myModule = require('./module'); myModule.setName('BYVoid'); myModule.sayHello();
注意:模块是单例的,即无论多少次require,获得的都是同一个实例。
8.2把一个对象封装到模块中
//hello.js
function Hello() { var name; this.setName = function(thyName) { name = thyName; }; this.sayHello = function() { console.log('Hello ' + name); }; }; module.exports = Hello;
//gethello.js
var Hello = require('./hello'); hello = new Hello(); hello.setName('BYVoid'); hello.sayHello();
原理:exports本身仅仅是一个普通的空对象,即{}。
8.3包
包就是C#中的类库。
node中一个文件夹加上接口(index.js)再加上一个配置文件就是一个包。可以通过 npm init 命令根据提示一步一步创建一个标准的package.json配置。
二、核心模块。
1,全局对象
node中的全局对象是global,所有的全局变量都是global的属性,包括console、process等
全局变量process描述当前node的进程状态,process.nextTick(callback)的功能是为时间循环设置一项任务,node会在下次事件循环时调用callback.
console.log()
console.error()
console.trace()
2, util模块
util.inherits(constructor, superConstructor) 实现对象间的原型继承,但构造函数内部创造的属性和函数都不会被继承
var util = require('util'); function Base() { this.name = 'base'; this.base = 1991; this.sayHello = function() { console.log('Hello ' + this.name); }; } Base.prototype.showName = function() { console.log(this.name); }; function Sub() { this.name = 'sub'; } util.inherits(Sub, Base); var objBase = new Base(); objBase.showName(); objBase.sayHello(); console.log(objBase); var objSub = new Sub(); objSub.showName(); //objSub.sayHello(); console.log(objSub);
util.inspect(object,[showHidden],[depth],[colors])是一个将任意对象转换 为字符串的方法, 通常用于调试和错误输出。
util还提供了util.isArray()、 util.isRegExp()、 util.isDate()、util.isError() 四个类型测试工具,以及 util.format()、util.debug() 等工具
3,events模块。
监听和触发事件:
var events = require('events'); var emitter = new events.EventEmitter(); emitter.on('someEvent', function(arg1, arg2) { console.log('listener1', arg1, arg2); }); emitter.on('someEvent', function(arg1, arg2) { console.log('listener2', arg1, arg2); }); emitter.emit('someEvent', 'byvoid', 1991);
EventEmitter提供的函数:
EventEmitter.on(event, listener)
EventEmitter.emit(event, [arg1], [arg2], [...])
EventEmitter.once(event, listener)
EventEmitter.removeListener(event, listener)
EventEmitter.removeAllListeners([event])
4,文件操作 - fs模块
fs.readFile(filename,[encoding],[callback(err,data)])
fs.readFileSync(filename, [encoding])
fs.open(path, flags, [mode], [callback(err, fd)])
fs.read(fd, buffer, offset, length, position, [callback(err, bytesRead,
buffer)])
5,http模块
//app.js
var http = require('http'); http.createServer(function(req, res) { res.writeHead(200, {'Content-Type': 'text/html'}); res.write('<h1>Node.js</h1>'); res.end('<p>Hello World</p>'); }).listen(3000); console.log("HTTP server is listening at port 3000.");
http客户端:
http.request(options, callback) 发起 HTTP 请求,以下是发送post请求的代码:
var http = require('http'); var querystring = require('querystring'); var contents = querystring.stringify({ name: 'byvoid', email: 'byvoid@byvoid.com', address: 'Zijing 2#, Tsinghua University', }); var options = { host: 'www.byvoid.com', path: '/application/node/post.php', method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length' : contents.length } }; var req = http.request(options, function(res) { res.setEncoding('utf8'); res.on('data', function (data) { console.log(data); }); }); req.write(contents); req.end();
http.get(options, callback)更加简便的方法用于处 理GET请求
var http = require('http'); http.get({host: 'www.byvoid.com'}, function(res) { res.setEncoding('utf8'); res.on('data', function (data) { console.log(data); }); });
http.request 或 http.get创建的对象是http.ClientRequest,请求完成返回的对象是http.ClientRequest
三、web开发
1,使用Express框架。
类似于asp.net ,express实现的功能:路由控制、模版解析支持、动态视图、缓存等功能。
express默认支持的模版引擎:jade、ejs
安装express: > npm install -g express
安装express命令行工具: >npm install -g express-generator
查看帮助信息: > express --help
建立web基本结构(使用jade模版引擎):> express myWeb
建立web基本结构(使用ejs模版引擎): > express -e myWeb2
进入刚建立的目录并初始化:>cd myWeb
:> npm install
启动:> npm start
此时浏览http://localhost:3000 可以看到第一个界面了。
关闭服务器 ctrl+c
创建的代码中,app.js是工程的入口。
2,路由控制。
app.js中,引用路由:var routes = require('./routes/index');
把Url“/”映射到路由:app.use('/', routes);
routes/index.js中路由的写法:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res) {
res.render('index', { title: 'Express' });
});
module.exports = router;
路由匹配:
/user/[username] :
app.get('/user/:username', function(req, res) {
res.send('user: ' + req.params.username);
});
3,视图。
布局、局部视图跟asp.net mvc一样。
<ul><%- partial('listitem', items) %></ul>
视图助手(asp.net mvc中的helper 方法)
var util = require('util'); app.helpers({ inspect: function(obj) { return util.inspect(obj, true); } }); app.dynamicHelpers({ headers: function(req, res) { return req.headers; } }); app.get('/helper', function(req, res) { res.render('helper', { title: 'Helpers' }); }); <%=inspect(headers)%>
4,数据库访问(以MongoDB为例)。
4.1 MongoDB。
MongoDB以文档的形式存储数据,一下是一个文档的示例:
{ "_id" : ObjectId( "4f7fe8432b4a1077a7c551e8" ),
"uid" : 2004,
"username" : "byvoid",
"net9" : { "nickname" : "BYVoid",
"surname" : "Kuo",
"givenname" : "Carbo",
"fullname" : "Carbo Kuo",
"emails" : [ "byvoid@byvoid.com", "byvoid.kcp@gmail.com" ],
"website" : "http://www.byvoid.com",
"address" : "Zijing 2#, Tsinghua University" }
}
4.2 连接数据库。
安装MongoDB.
package.json中添加依赖代码:
"dependencies": {
"express": "~4.2.0",
"static-favicon": "~1.0.0",
"morgan": "~1.0.0",
"cookie-parser": "~1.0.1",
"body-parser": "~1.0.0",
"debug": "~0.7.4",
"jade": "~1.3.0",
"mongodb":">=0.9.9"
}
运行: > cd myWeb
> npm install
工程目录中创建settings.js文件,代码如下:
module.exports = {
cookieSecret: 'microblogbyvoid',
db: 'microblog',
host: 'localhost',
};
注:db是数据库名称,host是数据库的地址,cookieSecret用于Cookie加密与数据库无关。
创建models子目录,并在其中添加db.js文件,内容是:
var settings = require('../settings'); var Db = require('mongodb').Db; var Connection = require('mongodb').Connection; var Server = require('mongodb').Server; module.exports = new Db(settings.db, new Server(settings.host, Connection.DEFAULT_PORT, {}));
注:通过module.exports输出了创建的数据库链接。
使用:
var mongodb = require('./db'); function User(user) { this.name = user.name; this.password = user.password; }; module.exports = User; User.prototype.save = function save(callback) { // 存入 Mongodb 的文档 var user = { name: this.name, password: this.password, }; mongodb.open(function(err, db) { if (err) { return callback(err); } // 读取 users 集合 db.collection('users', function(err, collection) { if (err) { mongodb.close(); return callback(err); } // 为 name 属性添加索引 collection.ensureIndex('name', {unique: true}); // 写入 user 文档 collection.insert(user, {safe: true}, function(err, user) { mongodb.close(); callback(err, user); }); }); }); }; User.get = function get(username, callback) { mongodb.open(function(err, db) { if (err) { return callback(err); } // 读取 users 集合 db.collection('users', function(err, collection) { if (err) { mongodb.close(); return callback(err); } // 查找 name 属性为 username 的文档 collection.findOne({name: username}, function(err, doc) { mongodb.close(); if (doc) { // 封装文档为 User 对象 var user = new User(doc); callback(err, user); } else { callback(err, null); } }); }); }); };
四,其他。
1,模块加载机制。
核心模块已经被编译成二进制代码,可以直接require获取,如 require('fs');
require文件模块的时候,如果指明了路径则按指定的加载,如果没有指定,则去node_modules目录加载。
即使多次require同一个模块, 加载到的仍是同一个对象,因为node根据实际文件名把加载过的文件模块缓存了。
2,日志功能。
启用日志功能,需要以产品模式运行express : > NODE-ENV=production node app.js
记录访问日志和错误日志:
var fs = require('fs');
var accessLogfile = fs.createWriteStream('access.log', {flags: 'a'});
var errorLogfile = fs.createWriteStream('error.log', {flags: 'a'});
至于错误日志,需要单独实现错误响应,修改如下:
app.configure('production', function(){
app.error(function (err, req, res, next) {
var meta = '[' + new Date() + '] ' + req.url + '\n';
errorLogfile.write(meta + err.stack + '\n');
next();
});
});
3,javascript的作用域。
JavaScript的作用域是由函数来决定的,if、for语句中的花括号不是独立的作用域。
if (true) {
var somevar = 'value';
}
console.log(somevar); // 输出 value
在一个函数中定义的变量只对这个函数内部可见。
4,call 和 apply 的用法。
var someuser = {
name: 'byvoid',
display: function(words) {
console.log(this.name + ' says ' + words);
}
};
var foo = {
name: 'foobar'
};
someuser.display.call(foo, 'hello'); // 输出 foobar says hello
5,bind的用法。
var someuser = { name: 'byvoid', func: function() { console.log(this.name); } }; var foo = { name: 'foobar' }; foo.func = someuser.func; foo.func(); // 输出 foobar foo.func1 = someuser.func.bind(someuser); foo.func1(); // 输出 byvoid func = someuser.func.bind(foo); func(); // 输出 foobar func2 = func; func2(); // 输出 foobar bind绑定参数列表: var person = { name: 'byvoid', says: function(act, obj) { console.log(this.name + ' ' + act + ' ' + obj); } }; person.says('loves', 'diovyb'); // 输出 byvoid loves diovyb byvoidLoves = person.says.bind(person, 'loves'); byvoidLoves('you'); // 输出 byvoid loves you
6, === 和 == 的区别。
==包含隐式转换。
7,原型、原型链。
prototype 、 _proto_
Object 、Function
Object.prototype 是所有对象的祖先,Function.prototype 是所有函数的原型,包括构造函数。
参考:《Node.js从入门到精通》
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?