Node.js 开发体验



           by QLeelulu
编程思想的改变
//node.js
                               var data;
//传统代码                         fs.readFile('file.txt',
var file = open('file.txt');      function(err, data){
var data = file.read();             data = data;
doSomething(data);                }
                               );
                               doSomething(data);
异步与回调
可读性
//传统的代码
var user = db.user.get('name');
var post = db.post.get(user.id);
var tags = db.tags.get(post.id);

              //异步回调方式
              db.user.get('name', function(err, user){
                  if(err) throw err;
                  db.post.get(user.id, function(err, post){
                      if(err) throw err;
                      db.tags.get(post.id, function(err, tags){
                          if(err) throw err;
                          //doWithResults();
                      });
                  });
              });
//传统代码
var value = Memcache.get('key');
if(!value){
   value = db.get('key');
   Memcache.set('key', value);
}
// 对value进行处理
                           //异步回调方式
                           function doWithValue(value){
                               // 对value进行处理
                           }
                           Memcache.get('key', function(err, value){
                               if(value){
                                  doWithValue(value);
                               }else{
                                  db.get('key', function(err, value){
                                      Memcache.set('key', value);
                                      doWithValue(value);
                                  });
                               }
                           });
原来流程清晰的代码,
可读性差了,
流程看起来也有点乱了
解决方案
●   封装代码
●   “ 编译”
    ●   https://github.com/Sage/streamlinejs

●   辅助函数
    ●   https://github.com/willconant/flow-js
    ●   http://howtonode.org/step-of-conductor
flow.exec(                         Flow-js 示例代码
     function() {
         fs.rename("/tmp/hello", "/tmp/world", this);
     },function(err) {
         if (err) throw err;
         fs.stat("/tmp/world", this)
     },function(err, stats) {
         if (err) throw err;
         sys.puts("stats: " + JSON.stringify(stats));
     }
);
                               其实吧,只是权宜之计~
更多 Flow control / Async goodies




https://github.com/joyent/node/wiki/modules#async-flow
Coroutine( 协程 )?

Cooperative threading of any sort is a bad idea.
                                     --ry@jsconf2010




     ●
      讨论:
         ●
           http://shiningray.cn/node-js-coroutine.html
         ●
           http://news.ycombinator.com/item?id=1549168
并行
博客首页:
var data = {};
// 获取最新10篇博客文章
db.getPosts(10, function(err, posts){
    data.posts = posts;
});
// 获取最新10条评论
db.getComments(10, function(err, comments){
    data.comments = comments;
});
// 获取Tags列表
db.getTags(function(err, tags){
    data.tags = tags;
});
// view.render(data);
                      注: db 的方法都为异步操作
并行获取数据很好很强大,
可是,
怎么知道全部数据都获取完了呢?
function Combo(callback) {
  this.callback = callback;
  this.items = 0;
}
Combo.prototype = {
  add: function () {
    this.items++;
  },
  finishOne: function () {
    this.items--;
    this.check();
  },
  check: function(){
     if (this.items == 0) {
       this.callback.apply(this);
     }

};
  }                                   并行辅助函数
                                    改自: http://howtonode.org/control-flow
var data = {};
var combo = new Combo(function(){
    view.render(data);
});                          最终回调
// 获取最新10篇博客文章
combo.add();
db.getPosts(10, function(err, posts){
    data.posts = posts;
    combo.finishOne();
});
// 获取最新10条评论
combo.add();
db.getComments(10, function(err, comments){
    data.comments = comments;
    combo.finishOne();
});
// ….
                              Combo 示例代码
Google V8 与 单线程
线程模型



                主线程




●
  主线程从左到右同时表示时间线      红色线代表的异步操作返回
●
  旁边的箭头代表异步操作         时,会发生什么情况呢?
●
  主线程上的色块代表异步操作返回后,
  执行代码所需的时间
var t;
function loop(){
    t = Date.now();
    for(var i=0; i< 10000*100000; i++){
        //console.log(i);
    }
};

function hello(){
    console.log((Date.now() - t) + 'ms');
};

setTimeout(loop, 100);
setTimeout(hello, 100);
●   主线程代码同步串行执行
●   同一时间只有一个回调函数在执行
●   异步回调会放到主线程的执行队列中,
    如果主线程正在执行其他代码,则等待
    调度,否则马上执行
高并发环境下呢?
var http = require('http');
http.createServer(function (req, res) {
   for(var i=0; i < 100*100000; i++){ }
   res.writeHead(200);
   res.end('Hello World');
}).listen(8080, "127.0.0.1");
Web Worker
●   耗 CPU 的操作放到 worker 中,
    不阻塞主进程
●   多 CPU 支持
●   目前 Node.js 还不支持 Web Worker
    ●
        In future versions, Node will be able to fork new
        processes (using the Web Workers API ) which
        fits well into the current design. – nodejs.org
    ●   https://github.com/pgriess/node-webworker
异常处理
var fs = require('fs');
try{
  fs.readFile('noFile',
     function(err, data){    如果异步回
       if (err) throw err;   调中抛出异
       console.log(data);    常会?
     }
  );
}catch(e){
  console.log('error');
}
异步回调函数外部 ,
无法捕获到异步回调函数内部的异常
process.on('uncaughtException', fn)

  可以捕获到任何未捕获的异常



      可是,
      没有了上下文变量
process.on('uncaughtException', function (err) {
    log(err);
});
http.createServer(function(req, res){
    try {
      mvcHandler(req, res);
    }                          如果此函数内部
    catch(e){                  有异步回调函数
      res.writeHead(200);      中抛出异常,客
      res.end('Server Error'); 户端则会得不到
    }                          响应
}).listen(8080, "127.0.0.1");
Express 中也存在该问题,
如果你有解决方案,
欢迎与我交流
调试




●   http://cnodejs.org/blog/?p=911
ECMAScript 5
●   Array
    ●   indexOf(), lastIndexOf(),
    ●   forEach(), map(), reduce(), filter(),
        every(), some()
●   JSON
    ●   JSON.parse(), JSON.stringify()
●   Object.keys()
●   Date.parse(), Date.now()
●   __defineGetter__, __defineSetter__
●
    更多 :http://davidflanagan.com/Talks/es5/slides.html
生产环境中,
怎样保证服务始终运行着?
Forever

●   确保脚本在持续运行着
●   Github: https://github.com/indexzero/forever
●   [sudo] npm install forever -g
●   forever start run.js
THX


Q&A
联系我
●

●
  http://qleelulu.cnblogs.com
●
  http:// 微博平台 /qleelulu
●
  qleelulu#gmail.com

Node.js开发体验

  • 1.
  • 2.
  • 3.
    //node.js var data; //传统代码 fs.readFile('file.txt', var file = open('file.txt'); function(err, data){ var data = file.read(); data = data; doSomething(data); } ); doSomething(data);
  • 4.
  • 5.
    可读性 //传统的代码 var user =db.user.get('name'); var post = db.post.get(user.id); var tags = db.tags.get(post.id); //异步回调方式 db.user.get('name', function(err, user){ if(err) throw err; db.post.get(user.id, function(err, post){ if(err) throw err; db.tags.get(post.id, function(err, tags){ if(err) throw err; //doWithResults(); }); }); });
  • 6.
    //传统代码 var value =Memcache.get('key'); if(!value){ value = db.get('key'); Memcache.set('key', value); } // 对value进行处理 //异步回调方式 function doWithValue(value){ // 对value进行处理 } Memcache.get('key', function(err, value){ if(value){ doWithValue(value); }else{ db.get('key', function(err, value){ Memcache.set('key', value); doWithValue(value); }); } });
  • 7.
  • 8.
    解决方案 ● 封装代码 ● “ 编译” ● https://github.com/Sage/streamlinejs ● 辅助函数 ● https://github.com/willconant/flow-js ● http://howtonode.org/step-of-conductor
  • 9.
    flow.exec( Flow-js 示例代码 function() { fs.rename("/tmp/hello", "/tmp/world", this); },function(err) { if (err) throw err; fs.stat("/tmp/world", this) },function(err, stats) { if (err) throw err; sys.puts("stats: " + JSON.stringify(stats)); } ); 其实吧,只是权宜之计~
  • 10.
    更多 Flow control/ Async goodies https://github.com/joyent/node/wiki/modules#async-flow
  • 11.
    Coroutine( 协程 )? Cooperativethreading of any sort is a bad idea. --ry@jsconf2010 ● 讨论: ● http://shiningray.cn/node-js-coroutine.html ● http://news.ycombinator.com/item?id=1549168
  • 12.
  • 13.
    博客首页: var data ={}; // 获取最新10篇博客文章 db.getPosts(10, function(err, posts){ data.posts = posts; }); // 获取最新10条评论 db.getComments(10, function(err, comments){ data.comments = comments; }); // 获取Tags列表 db.getTags(function(err, tags){ data.tags = tags; }); // view.render(data); 注: db 的方法都为异步操作
  • 14.
  • 15.
    function Combo(callback) { this.callback = callback; this.items = 0; } Combo.prototype = { add: function () { this.items++; }, finishOne: function () { this.items--; this.check(); }, check: function(){ if (this.items == 0) { this.callback.apply(this); } }; } 并行辅助函数 改自: http://howtonode.org/control-flow
  • 16.
    var data ={}; var combo = new Combo(function(){ view.render(data); }); 最终回调 // 获取最新10篇博客文章 combo.add(); db.getPosts(10, function(err, posts){ data.posts = posts; combo.finishOne(); }); // 获取最新10条评论 combo.add(); db.getComments(10, function(err, comments){ data.comments = comments; combo.finishOne(); }); // …. Combo 示例代码
  • 17.
    Google V8 与单线程
  • 18.
    线程模型 主线程 ● 主线程从左到右同时表示时间线 红色线代表的异步操作返回 ● 旁边的箭头代表异步操作 时,会发生什么情况呢? ● 主线程上的色块代表异步操作返回后, 执行代码所需的时间
  • 19.
    var t; function loop(){ t = Date.now(); for(var i=0; i< 10000*100000; i++){ //console.log(i); } }; function hello(){ console.log((Date.now() - t) + 'ms'); }; setTimeout(loop, 100); setTimeout(hello, 100);
  • 20.
    主线程代码同步串行执行 ● 同一时间只有一个回调函数在执行 ● 异步回调会放到主线程的执行队列中, 如果主线程正在执行其他代码,则等待 调度,否则马上执行
  • 21.
  • 22.
    var http =require('http'); http.createServer(function (req, res) { for(var i=0; i < 100*100000; i++){ } res.writeHead(200); res.end('Hello World'); }).listen(8080, "127.0.0.1");
  • 24.
    Web Worker ● 耗 CPU 的操作放到 worker 中, 不阻塞主进程 ● 多 CPU 支持 ● 目前 Node.js 还不支持 Web Worker ● In future versions, Node will be able to fork new processes (using the Web Workers API ) which fits well into the current design. – nodejs.org ● https://github.com/pgriess/node-webworker
  • 25.
  • 26.
    var fs =require('fs'); try{ fs.readFile('noFile', function(err, data){ 如果异步回 if (err) throw err; 调中抛出异 console.log(data); 常会? } ); }catch(e){ console.log('error'); }
  • 27.
  • 28.
    process.on('uncaughtException', fn) 可以捕获到任何未捕获的异常 可是, 没有了上下文变量
  • 29.
    process.on('uncaughtException', function (err){ log(err); }); http.createServer(function(req, res){ try { mvcHandler(req, res); } 如果此函数内部 catch(e){ 有异步回调函数 res.writeHead(200); 中抛出异常,客 res.end('Server Error'); 户端则会得不到 } 响应 }).listen(8080, "127.0.0.1");
  • 30.
  • 31.
    调试 ● http://cnodejs.org/blog/?p=911
  • 32.
    ECMAScript 5 ● Array ● indexOf(), lastIndexOf(), ● forEach(), map(), reduce(), filter(), every(), some() ● JSON ● JSON.parse(), JSON.stringify() ● Object.keys() ● Date.parse(), Date.now() ● __defineGetter__, __defineSetter__ ● 更多 :http://davidflanagan.com/Talks/es5/slides.html
  • 33.
  • 34.
    Forever ● 确保脚本在持续运行着 ● Github: https://github.com/indexzero/forever ● [sudo] npm install forever -g ● forever start run.js
  • 35.
    THX Q&A 联系我 ● ● http://qleelulu.cnblogs.com ● http:// 微博平台 /qleelulu ● qleelulu#gmail.com