Nodejs开发指南-笔记
第三章 异步式I/O与事件编程
3.1 npm install -g supervisor
supervisor app.js 当后台修改代码后,服务器自动重启,生效修改的代码,不用手动停止/启动
3.2 单线程异步I/O
减少了多线程的开销,对于操作系统,创建线程的开销很大,需分配内存、列入调度。同时线程切换时
需要内存换页,CPU的缓存被清空,切换回来时,需要重新从内存中读取信息,破坏了数据的局部性。
异步读取文件:
var fs = require('fs') fs.readFile('test.txt','utf-8',function(err,data){
if(err){
console.log(err);
}
else console.log(data);
}) console.log('end'); 输出:
end;
content of the test.txt
3.3模块和包
3.3.1、模块
什么是模块:
一个文件就是一个模块。
创建模块:
exports和require实现
举例说明
//module.js
var name;
exports.setName = function(thyname){
name = thyname;
} exports.getName = function(){
console.log(name);
} //getnodule.js
var module = require('./module') module.setName('xxx')
module.getName(); 对于对象的封装:
//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') var hello = new Hello();
hello.setName("xxx");
hello.sayHello();
3.3.2、包
将一个文件夹封装成一个模块,即所谓的包
(1)作为文件夹的模板
1、建立一个somepackage文件夹
2、在somepackage下建立index.js文件 (必须是index.js)
3、文件中写入
exports.hello=function(){
console.log('Hello World');
};
在somepackage文件夹外建立一个getpackage.js文件
写入
var somepackage=require('./somepackage');
somepackage.hello();
3.2.2 package.json
在主目录下创建package.json,写入:
{
"main":"./lib/interface.js"
}
在主目录中建立lib子文件夹,并在其中创建interface.js文件,在文件中写入 exports.hello=function(){
console.log('Hello Node.js');
};
运行上面的getpackage.js得到相同的结果。
Node.js在调用某个包时,会首先检查包中package.json中的main字段,将其作为包的接口模块,如果main不存在,会尝试寻找index.js或者index.node作为包的接口
3.4nodejs的包管理器npm
npm install [包名]
npm install -g [包名]//全局目录安装
创建的全局模式的包,不能直接require使用,需要创建全局链接
npm link [包名]
./node_moudles/[包名] -> /usrt/local/lib/node_moudles/express
3.5npm包的发布
1、npm init 填写好package.json信息
2、npm adduser 按照提示填写账号信息,用于以后维护包
3、npm publish 发布包
打开浏览器 http://npmjs.org/可以查找到,而且在世界商任意一台主机上,都可以用npm install [包名]来安装你发布的包
3.6调试
3.6.1命令行调试
在设置断点的代码处添加debugger
node debug app.js
进入调试界面,help查看调试命令
3.6.2远程调试
//在一个终端里(不加port,默认是5858)
node --debug-brk[=port] app.js
或 node --debug[=port] app.js
//在另一个终端中
node debug 127.0.0.1:5858或 node debug 127.0.0.1:[port]
3.6.3node-inspector调试
npm install -g node-inspector
//运行脚本
node --debug-brk=5858 app.js
//启动node-inspector
$ node-inspector
//打开浏览器
http://127.0.0.1:8080/debug?port=5858
第四章nodejs核心模块
4.1全局对象
永远使用var定义变量,避免引入全局变量,因为你全局变量会污染明明空间。
4.1.1 process.argv命令行参数数组
第一个参数是node 第二个参数是脚本文件名,第三个参数是运行参数
4.1.2 process.nextTick(callback)
为事件循环设置一项任务,将复杂的任务,拆分成一个个较小的事件
举例说明:
function doSomething(callback){
compile()
callback()
} doSomething(function onEnd){
compute()
}
改进后
function doSomething(callback){
compile()
process.nextTick(callback)
} doSomething(function onEnd){
compute()
}
改进后的程序会把上面耗时的操作拆分位两个事件,减少每个事件的执行时间,提高时间响应效率。
4.2常用工具util
4.2.1 util.inspect将人已对象转换成字符串。
util.inspect(object.[showHidden],[depth],[color])
showHidden可选参数,如果是true,输出更过隐藏信息
depth可选参数,最大递归层数,默认2,指定为null表示不想递归层数,完整遍历。
color可选参数,true表示输出格式以ANSI颜色编码,终端显示更漂亮。
4.3事件驱动events(最重要的模块)
4.3.1事件发射器
events.EventEmitter 时间发射和时间监听
var events = require('events')
var emitter = new events.EventEmitter() emitter.on('someEvent',function(arg1,arg2){
console.log('listen ',arg1,arg2)
}) emitter.emit('someEvent','byvoid',1991)
输出
listen byvoid 1991
4.4文件系统fs
4.4.1 fs.readFile()异步读取文件
fs.readFile('filename','utf-8',function(err,data){
if(err){
console.log(err)
}
else{
console.log(data)
}
})
4.4.2 fs.readFileSync(filename,[encoding])同步读取文件
4.4.3 fs.open(path,flags,[mode],[callback(err,fd)])
path:文件路径, flags:r,r+,w,w+,a,a+ 两个必选参数
mode:用于创建文件时给文件的指定权限,默认是0666
4.4.4 fs的其他常用函数:
1)读取文件
异步:fs.readFile(filename,[encoding],[callback(err,data)])
同步:fs.readFileSync(filename,[encoding])
2)写入文件(清空原有的)
异步:fs.writeFile(filename,data,[encoding],[callback(err)])
同步:fs.writeFileSync(filename,data,[encoding])
3)追加写入文件
异步:fs.appendFile(filename,data,[encoding],[callback(err)])
同步:fs.appendFileSync(filename,data,[encoding])
4)删除文件
异步fs.unlink(path,[callbacl(err)])
同步:fs.unlinkSync(path)
5)创建目录
异步:fs.mkdir(path,[mode],[callback(err)])
同步:fs.mkdirSync(path,[mode])
6)删除目录
异步:fs.rmdir(path,[callback(err)])
同步:fs.rmdirSync(path)
7)读取目录(读取目录下的所有文件,输出一个数组)
异步:fs.readdir(path,[callback(err)])
同步:fs.readdirSync(path)
8)获取文件真实路径
异步:fs.realpath(filename,[callback(err,files)])
同步:fs.realpathSync(filename)
9)更名
异步:fs.rename(path1,path2,[callback(err)])
同步:fs.renameSync(path1,path2)
10)更改权限
异步:fs.chmod(path,mode,[callback(err)])
同步:fs.chmodSync(path,mode)
11)更改所有权
异步:fs.chown(path,uid,gid,[callback(err)])//uid和gid为整形,linux下运行id命令可以查询
同步:fs.chownSync(path,uid,gid)
第六章 Nodejs进阶话题
6.1 加载缓存
nodejs不会重复加载,这是因为nodejs通过文件名缓存所有加载过的文件模块,所以以后再放问到时,就不会重复加载了。require后只需加载一次
6.2 Nodejs应用部署
6.2.1 不支持故障恢复
当程序发生错误时,后台直接垮掉
6.2.2 没有日志输出
解决方法:Express支持另种运行模式:开发模式和产品模式。前者用于调试,后者用于部署。
只需设置NODE_ENV变量即可,NODE_ENV = production实现产品模式,node app.js可以看到
Express server listening on port 3000 in production
在app.js的最上方添加一下代码,实现日志打印
var fs = require('fs'); var accessLogfile = fs.createWriteStream('access.log',{flags:'a'});
var errorLogfile = fs.createWriteStream('error.log',{flags:'a'});
app.use(express.logger({stream: accessLogfile}))
//对于错误日志,需要单独实现错误响应 app.config('production',function(){
app.error(function(err,req,res,next){
var meta = '['+ new Date() +']' + req.url+'\n';
errorLogfile.write(meta+err.stack+'\n');
next();
})
})
6.2.3 无法利用多核提高性能(单线程)
解决方法:cluster模块。cluster的功能是生成与当前进程相同的子进程,并允许子进程和父进程之间共享端口。
调用cluster模块,将主进程生成若干工作进程。
6.2.4 独占端口
解决方法:利用ngix,通过反向代理实现nodejs虚拟主机
下面举例配置文件
server {
listen 80;
server_name mysite.com;
location /{
proxy_pass http://localhost:3000;
}
}
该配置文件的功能是,监听访问mysite.com 80端口的请求,并将多有的请求转发给localhost:3000
6.2.5 需要手动启动(重启服务器的化)
解决方法:编写开机脚本
6.3 nodejs不适合做什么
6.3.1 不适合计算密集型程序
6.3.2 不适合单用户多任务应用。
node适合解决大量并发请求,单用户不存在并发请求。
6.3.3 不适合逻辑十分复杂的事物
node更善于处理逻辑简单但访问频繁的任务。
附录A JavaScript的高级特性
A-1、作用域
js的作用域是通过函数来定义的。变量的搜索由函数内向函数外扩展
var scop = "global" var f = function(){
console.log(scop);//输出undefined
scop = "f";
}
注:js访问未定义或着定义了但未初始化的变量,都是undefined
A-2、对象
js只有对象,对象就是对象,不是类的实例
js中的对象不是基于类实现的,而是基于原型实现的。
1、var foo = {} //即为对象
foo.prop_1 = 'bar'
2、使用对象初始化器创建对象
var foo = {
prop1:'bar',
prop2:function(){
}
}
3、使用构造函数创建对象
function User(name, uri){
this.name = name;
this.uri = uri;
this.display = function(){
return this.name;
}
}
var someuser = new User('name','http://baidu.com')
4、上下文对象(call)
call可以实现继承。
user = {
name:"xxxx",
uri:'baudu.com',
display: function(words){
console.log(this.name+" "+words)
}
} var foo = {
name:'foobar'
}
user.display.call(foo,'hello')
输出: foobar hello
A-3、原型
利用原型来初始化对象
function Foo(){}
Foo.prototype.name = "user"
Foo..prototype.getName = function() {
return this.name
};
var foo = new Foo()
foo.getName()//输出user
举例说明构造函数内创建属性和原型定义成员函数的区别
function Foo(){
this.prop = "prop";
this.getProp = function(){
return this.prop
}
}
Foo.prototype.name = "user"
Foo..prototype.getName = function() {
return this.name
}; var foo1 = new Foo()
var foo2 = new Foo()
console.log(foo1.getProp ==foo2.getProp)//false
console.log(foo1.getName ==foo2.getName)//true
构造函数内定义的任何属性,包括函数在内都被重复构建,同一个构造函数产生的两个对象不共享实例。
所以尽量用原型定义成员函数,减少开销。
尽量在构造函数内定义一般成员,尤其是数组或对象,因为原型中定义的成员是多个实例共享的。
B、Nodejs编程规范
1、两个空格做缩进
2、分号做换行符
3、var定义变量 绝对不能使用赋值隐式定义的变量(全局变量,空间污染),确保每个语句定义一个变量,(不能定义多个变量,之间用','分割)
4、变量名和属性名(驼峰式命名空间)
5、对于函数定义,() {}之间要有一个空格
6、同意使用单引号
7、等号尽量使用===
8、命名函数
回调函数和构造函数,尽量给函数命名。
对于回调函数,Nodejs和第三方模块约定第一个参数是err
9、对象定义
所有成员函数,尽量用原型进行定义,属性在构造函数内定义,然后对构造函数用new进行对象的创建
Nodejs开发指南-笔记的更多相关文章
- nodejs开发指南读后感
nodejs开发指南读后感 阅读目录 使用nodejs创建http服务器; supervisor的使用及nodejs常见的调式代码命令了解; 了解Node核心模块; ejs模板引擎 Express 理 ...
- 《nodejs开发指南》微博实例express4.x版
之前一直执着于前端开发,最近几天,开始学起了nodejs.作为一名前端开发者,见到这样一门用javascript写的后台自然是很激动的.但是,后台毕竟不同于前端,在学习的过程中,还是会遇到不少问题. ...
- 《NodeJS开发指南》第五章微博实例开发总结
所有文章搬运自我的个人主页:sheilasun.me <NodeJS开发指南>这本书用来NodeJS入门真是太好了,而且书的附录部分还讲到了闭包.this等JavaScript常用特性.第 ...
- 《NodeJs开发指南》第五章微博开发实例的中文乱码问题
在<NodeJs开发指南>第五章,按照书中的要求写好微博实例后,运行代码,发现中文显示出现乱码,原因是:views文件夹下的ejs文件的编码格式不是utf-8. 解决方法:以记事本方式打开 ...
- Django Web开发指南笔记
Django Web开发指南笔记 语句VS表达式 python代码由表达式和语句组成,由解释器负责执行. 主要区别:表达式是一个值,它的结果一定是一个python对象:如:12,1+2,int('12 ...
- 读《nodejs开发指南》记录
最近看了一下<nodejs开发指南>发现nodejs在某些特定的领域由他自己的长处,适合密集计算但是业务逻辑比较简单的场景,如果做网站还是选择php吧,呵呵,这本书我除了第5章<用n ...
- 使用express4.x版、Jade模板以及mysql重写《nodejs开发指南》微博实例
最近阅读<nodejs开发指南>一书,书是不错的,然而其微博代码示例用的是express3.x,用些过时了,运行代码出现不少bug(我电脑安的是express4.x),于是用express ...
- [Lua游戏AI开发指南] 笔记零 - 框架搭建
一.图书详情 <Lua游戏AI开发指南>,原作名: Learning Game AI Programming with Lua. 豆瓣:https://book.douban.com/su ...
- nodejs 开发指南 书中小项目 代码
最近 在学习node.js 先看了下语法 ,然后就看这个开发指南感觉书还是很有用,但是代码太旧了,网上也没有最新的,所以就自己查着前人的痕迹和自己修改,现在可以跑了. https://github.c ...
随机推荐
- js调用高德API获取所在当前城市
可以在js代码中直接调用API接口,获取所处当前城市信息,代码如下: <script type="text/javascript"> function getCurre ...
- poj -3262 Protecting the Flowers (贪心)
http://poj.org/problem?id=3262 开始一直是理解错题意了!!导致不停wa. 这题是农夫有n头牛在花园里啃花朵,然后农夫要把它们赶回棚子,每次只能赶一头牛,并且给出赶回每头牛 ...
- Support Library(5)在eclipse中导入SupportXXXDemos
Support4Demos只用一个v4.,Support7Demos只要v13.jar, SupportAppNavigation只要一个v4.jar. Support7Demos 需要资源全部v7系 ...
- Remember that ordinal parameters are 1-based!
问题发生的原因是:hql语句里不需要参数,却添加了一个参数,删掉添加参数的语句就可以了!
- SQL group by分组查询(转)
本文导读:在实际SQL应用中,经常需要进行分组聚合,即将查询对象按一定条件分组,然后对每一个组进行聚合分析.创建分组是通过GROUP BY子句实现的.与WHERE子句不同,GROUP BY子句用于归纳 ...
- HDU 1525 (博弈) Euclid's Game
感觉这道题用PN大法好像不顶用了,可耻地看了题解. 考虑一下简单的必胜状态,某一个数是另一个数的倍数的时候是必胜状态. 从这个角度考虑一下:游戏进行了奇数步还是偶数步决定了哪一方赢. 如果b > ...
- Codeforces Round #276 (Div. 2)
A. Factory 题意:给出a,m,第一天的总量为a,需要生产为a%m,第二天的总量为a+a%m,需要生产(a+a%m)%m 计算到哪一天a%m==0为止 自己做的时候,把i开到1000来循环就过 ...
- Ubuntu中文输入法的安装
Ubuntu上的输入法主要有小小输入平台(支持拼音/二笔/五笔等),Fcitx,Ibus,Scim等.其中Scim和Ibus是输入法框架. 在Ubuntu的中文系统中自带了中文输入法,通过Ctrl+S ...
- codevs 1228 苹果树
dfs序+线段树 #include<iostream> #include<cstdio> #include<cstring> #include<algorit ...
- 【英语】Bingo口语笔记(73) - 以tly,tely结尾的误读