AirJD 焦点
AirJD

没有录音文件
00:00/00:00
加收藏

Node.JS软件开发实践教程分享 by 范圣刚

发布者 jser
发布于 1437701206627  浏览 5037 关键词 Node.JS 
分享到

第1页

软件开发实践分享

@范圣刚 - 2013.12.05



第2页

主要内容

模块 异常捕捉和错误处理

同步和异步 运⾏行与⽇日志 ⼏几个 Tips



第3页

模块(Modules)



第4页

模块组织



第5页

模块系统

• 使⽤用 require ⽅方法,使⽤用模块标识,返回导出的 API • 模块名称是字符串,可以包含路径 • 要从模块中导出的必须要明确指定

CommonJS 模块系统要求在 Node 中的实现



第6页

⽂文件和模块⼀一对⼀一

• 传⼊入模块标识字符串

• var http = require(‘http’)

• 也可以指定其中的⼀一种对象,⽽而不是所有对象

• var spawn = require(‘child_process’).spawn

• Node 本⾝身的模块,或是在 node_modules 下⾯面 的模块,可以直接使⽤用 module 的 identifier

• 否则需要使⽤用 / 指定路径

• require(‘./mymodule’); 或者全路径 • require(‘/path/to/mymodule’);

• 扩展名可以是 .js, .node, .json



第7页

模块加载过程

http://nodejs.org/api/modules.html



第8页

模块循环引用的问题

http://nodejs.org/api/modules.html



第9页

模块的导出:exports



第10页

单次加载的问题



第11页

导出对象的封装

var Hello = require(‘./singleobject’).Hello



第12页

模块的导出:module.exports



第13页

作为 class 导出



第14页

模块复用:node_modules

•package.json  •git  •npm init  •npm adduser  •npm publish  •本地测试:npm install . -g

测试和发布⾃自⼰己的 Module



第15页

同步和异步



第16页

使用 Underscore.js

简化同步操作



第17页

异步编程的常见陷阱



第18页

异步操作的工作流

同步遍历⽂文件并读取内容的代码



第19页

改成异步后的代码



第20页

Async 的工作流控制和任务组织

简化异步数据集和函数集操作的利器



第21页

Async:简化数据集操作



第22页

Async:简化任务集操作

series & parallel



第23页

Async:waterfall



第24页

Async:queue



第25页

 async.waterfall([



  function (cb) {



   engine.speak(option, cb);



  }



  , function (voice, cb) {



   var mp3file = voice_temp_dir + voice_prefix + entry._id + '.mp3';



   async.parallel([



    function (cb) {







fs.writeFile(mp3file, voice, {encoding: 'base64'}, cb); 



    }



    , function (cb) {







TranslationMemory.findByIdAndUpdate(entry._id, {'mp3voice':



voice.toString('base64'), 'datetime': new Date}, cb);



    }



    ]



    , function (err, results) {



     return cb(err, results);



    }



   );



  }



  ]



  , function (err, result) {



   return callback(err, result);



  }



 );







Async ⽰示例:waterfall + parallel



第26页

var updateAudio = function (limit, callback) {  async.waterfall([   function(cb) {    TranslationMemory.find({mp3voice: {$exists: false}}, null, {limit: 1000}, cb);   }   , function(entries, cb) {    async.eachLimit(entries, limit, speakAndUpdate, cb);   }   ]   , function(err, result) {    return callback(null, result);   }  ); };

Async ⽰示例:waterfall + eachLimit



第27页

异常捕捉和错误处理



第28页

assert



第29页

顺序执行和异常捕捉



第30页

JSON 解析的异常捕捉



第31页

//Define divider as a syncrhonous function var divideSync = function(x,y) {

// if error condition? if ( y === 0 ) {

// "throw" the error safely by returning it return new Error("Can't divide by zero"); } else { // no error occured, continue on return x/y; } };

!

// Divide 4/0 result = divideSync(4,0); // did an error occur? if ( result instanceof Error ) {

// handle the error safely console.log('4/0=err', result); } else { // no error occured, continue on console.log('4/0='+result); }

同步执⾏行返回错误对象



第32页

异步(嵌套)回调和异常处理



第33页

回调内抛出的异常

function async(callback) { process.nextTick(function(){ throw new Error("Something went wrong"); callback(); });

}

!

try { async(function(){ console.log("It worked!"); });

} catch(error) { console.log("This is never printed.");

}



第34页

未捕获异常的处理

process.on('uncaughtException', function(err) { // handle the error safely console.log(err);

});

!

// the asynchronous or synchronous code that emits the otherwise uncaught error var err = new Error('example'); throw err;



第35页

var divide = function(x,y,next) { // if error condition? if ( y === 0 ) { // "throw" the error safely by calling the completion callback // with the first argument being the error next(new Error("Can't divide by zero")); } else { // no error occured, continue on next(null, x/y); }

};

!

divide(4,0,function(err,result){ // did an error occur? if ( err ) { // handle the error safely console.log('4/0=err', err); } else { // no error occured, continue on console.log('4/0='+result); }

});

异步返回错误



第36页

//Definite our Divider Event Emitter var events = require('events'); var Divider = function(){

events.EventEmitter.call(this); };  require('util').inherits(Divider, events.EventEmitter); // Add the divide function Divider.prototype.divide = function(x,y){

// if error condition? if ( y === 0 ) {

// "throw" the error safely by emitting it var err = new Error("Can't divide by zero"); this.emit('error', err); } else { // no error occured, continue on this.emit('divided', x, y, x/y); } // Chain return this; };

!

// Create our divider and listen for errors var divider = new Divider(); divider.on('error', function(err){

// handle the error safely console.log(err); }); divider.on('divided', function(x,y,result){ console.log(x+'/'+y+'='+result); });

!

// Divide divider.divide(4,2).divide(4,0);

使⽤用 Event



第37页

运行和日志



第38页

Linux 上后台运行



第39页

以生产环境运行

NODE_ENV=production node yourscript.js



第40页

故障恢复和进程管理 - forever

https://github.com/nodejitsu/forever



第41页

log4js

https://github.com/nomiddlename/log4js-node



第42页

数据库:Mongoose V3

•从 Node.js MongoDB driver 迁移到  Mongoose

http://mongodb.github.io/node-mongodb-native/ http://mongoosejs.com



第43页

app.getOneDocument = function(collection_name, query, callback) {  db.collection(collection_name).find(query).nextObject(callback); }

!

app.getAllDocuments = function(collection_name, query, callback) {  db.collection(collection_name).find(query).toArray(callback); }

!

app.setOneDocument = function(collection_name, query, update, callback) {  db.collection(collection_name).update(query, {$set: update}, callback); }

!

app.addOneDocument = function(collection_name, document, callback) {  db.collection(collection_name).insert(document, {safe: true}, callback); }

store.addOneDocument('event_security', event_signin, function(err, event_result) { });

对 MongoDB node.js driver 的简单封装



第44页

'use strict';

!

var mongoose = require('mongoose')  , Schema = mongoose.Schema  , ObjectId = Schema.ObjectId;

!

var app = module.exports = {};  var ProductSchema = new Schema({  amount: Number  , appname: String  , category: String  , course: {   id: String   , name: String

, level: Number , level_upgrade_after:Array

 }  , enabled: Boolean  , datetime: { type: Date, default: Date.now } });

!

app.ProductModel = mongoose.model('products', ProductSchema, 'products');

每个 schema 映射到⼀一个 MongoDB 的 collection



第45页

Mongoose Features

• Schemas  •schema 可以具有自定义的实例和静态方法,以及get/set  •Virtuals - 方便使用又不持久化到 MongoDB 

• Models  •创建:new … save() / create()  •find, findById, findOne, findOneAndUpdate, remove …  •validation 

• Middleware  •init, validate, save, remove(触发器)  •pre & post 

•其他:连接池,跨表查询,plugins等



第46页

总结

•操作系统:Ubuntu 12.04 64位  •托管:Linode 2GB * 3, 1-dev,2-production  •版本:使用 Git 进行版本控制和部署(gitlab)  •Web Server:Nginx 1.4.3(服务静态文件和代理)  •DataBase:MongoDB + Mongoose  •Load Balancer:Linode NodeBalancers  •进程管理:forever + init.d(service)  •日志:log4js + logrotate.d(转储,压缩,每天)  •同步和异步JS:Underscore + Async



第47页

开发小故事

•调试:node-inspector(webkit+远程调试)  •‘use strict’:全局变量;  •npm install <package_name> —save : 自动更

新 package.json 

•Canvas -> PhantomJS  •消息队列:kue -> RabbitMQ



第48页

我为什么使用 Node.js ?



我的开发⼯工具箱 Web 应⽤用 Apps 开发

⽹网络和系统编程 脚本和⼩小⼯工具

数据库 数据交换



现在

Node.js + Express + Backbone

Sencha Touch + PhoneGap

Node.js



以前

Ruby on Rails Java SSH iOS Android

C++



Node.js, Ruby MongoDB, redis

JSON



Ruby, C++

SQL Server, Oracle, MySQL

⼆二进制的 protocol,http urlencode



简单⾼高效



第49页

Node.js vs. Java (via PayPal)

•开发 

•构建过程使用更少的开发者,速度反而快一倍  •书写的代码行数要少33%  •文件个数少了 40% 

•性能 

•每秒处理的请求翻倍(Node.js 一核心,Java 五核 心) 

•平均响应时间下降了 35%(快了200ms)

https://www.paypal-engineering.com/2013/11/22/node-js-at-paypal/



第50页

不明觉厉

•examples -> Mocha  •express -> kraken  •callback -> Promise + Q.js  •libuv,v8, Linux C++



第51页

Thank you!



第52页

http://gitlab.org/



第53页

Performance



第54页

ab -n 10000 -c 1000



第55页

Node.js vs. Apache + PHP

1M20K HTTP REQUEST

Node.js

Apache + PHP



第56页

Node.js vs. Apache + Php

• Node.js is much faster than Apache+PHP • Many more requests per second • Higher transfer rate with much smaller number of

failed requests at the same time



第57页

Node.js vs. Go



第58页

Node.js vs. Go

• Go 的数据处理优于 Node.js(⽐比如运⾏行冒泡排 序)

• Node.js 的 HTTP 处理和伸缩性⽐比 Go 更有效率 • 团队经验(JavaScript Vs. ⼀一种全新的语⾔言)



支持文件格式:*.pdf
上传最后阶段需要进行在线转换,可能需要1~2分钟,请耐心等待。