Nodejs编程基础

这是一系列Nodejs实战第一季后的整理笔记,为了快速查找及记录

Node 功能的组织及重用

1.1.1、创建模块

定义Node模块
currency.js

/*exports 对象上只设定了两个属性。也就是说引入这个模块的代码只能访问到 canadianToUS
和 USToCanadian 这两个函数。而变量 canadianDollar 作为私有变量仅作用在 canadianToUS
和 USToCanadian 的逻辑内部,程序不能直接访问它。*/
var canadianDollar = 0.91;
functon roundTwoDecimals(amount){
  return Math.round(amount * 100)/100;
}
exports.canadianToUS = funtion(canadian){
  return roundTwoDecimals(candian * canadianDollar);
}
exports.USToCanadian = function(us){
  return roundTwoDecimals(us/canadianDollar);
}

引入一个模块
test-currency.js

var currency = require('./currency');
console.log(currency.canadianToUS(50));
console.log(currency.USToCanadina(30));

1.1.2 用module.exports微调模块的创建

module.exports返回一个Currency的构造函数(类似于class)

/*
最终在程序里导出的是 module.exports 。 exports 只是对 module.exports 的一个全
局 引 用 , 最 初 被 定 义 为 一 个 可 以 添 加 属 性 的 空 对 象 。 所 以 exports.myFunc 只 是
module.exports.myFunc 的简写
*/
var Currency = function(canadianDollar){
  this.canadianDollar = canadianDollar;
}
Currency.prototype.roundTwoDecimals = function(amount){
  return Math.round(amount * 100) / 100;
}
Currency.prototype.canadianToUS = function(canadian){
  return this.roundTwoDecimals(canadian * this.canadianDollar);
}
Currency.prototype.USToCanadian = function(us){
  return this.roundTwoDecimals(us / this.canadianDollar);
}
module.exports = exports = Currency;

1.2 异步编程技术

1.2.1 用回调处理一次性事件
回调是一个函数,它被当做参数传给异步函数
实现功能

  • 异步获取存放在JSON文件中的文章标题
  • 异步获取简单的HTML模板
  • 把那些标题组装到HTML页面中
  • 把HTML页面发送给用户
    title.json
[
  "node",
  "利于",
  "服务器"
]

template.html

<!doctype html>
<html>
  <head></head>
  <body>
    <h1>Lastest Posts</h1>
    <ul>
      <!--会被替换为标提-->
      <li>%</li>
    </ul>
  </body>
</html>

blog_recent.js

var http = require('http');
var fs = require('fs');
var server = http.createServer(function(req,res){
    getTitles(res);
}).listen(3000);
function getTitles(res){
    fs.readFile('./title.json',function(err,data){
        if(err) return hadError(err,res);
        getTemplate(JSON.parse(data.toString()),res);
    });
}
function getTemplate(titles,res){
    fs.readFile('./template.html',function(err,data){
        if(err) return hadError(err,res);
        formatHtml(titles,data.toString(),res);
    })
}
function formatHtml(titles,tmpl,res){
    var html = tmpl.replace('%',titles.join('<li></li>'));
    res.writeHead(200,{'Content-Type':'text/html'});
    res.end(html);
}
function hadError(err,res){
    console.log(err);
    res.end('Server Error');
}

1.2.2 用事件发射器处理重复性事件
echo服务器处理重复性事件的简单案例
用on方法响应事件
echo_server.js

var net = require('net');
var server = net.createServer(function(socket){
  #当读取到新数据时处理的data事件 once 只响应一次
  socket.once('data',function(data){
      socket.write(data);//数据被写回到客户端
    });
});
server.listen(8888);

运行 node echo_server.js
新打终端 telnet 127.0.0.1:8888

Paste_Image.png

简易聊天室
easy_chat.js

var events = require('events');
var net = require('net');
#设置
var channel = new events.EventEmitter();
channel.clients = {};
channel.subscriptions = {};
#绑定发射器
channel.on('join',function(id,client){
  #添加join事件的监听器,保存用户的client对象,以便程序可以将数据发送给用户
  this.clients[id] = client;
  #连接人数
  var num = "Welcome!\n" + 'Guest online:' + this.listeners('broadcast').length;
  client.write('num is '+ num);
  this.subscriptions[id] = function(senderId,message){
    #忽略发出这一广播数据的用户
    if(id != senderId){
      this.clients[id].write(id +':'+ message);
    }
  }
  #添加一个专门针对当前用户的broadcast事件监听器
  this.on('broadcast',this.subscriptions[id]);
});
#创建一个在用户断开连接时能打扫战场的监听器
channel.on('leave',function(id){
  channel.removeListener('broadcast',this.subscriptions[id]);
  channel.emit('broadcast',id,id+' has left the chat.\n');
});
#关闭聊天服务 但不关闭服务器
channel.on('shutdown',function(){
  channel.emit('broadcast','',"Chat has shut down.\n");
  channel.removeAllListeners('broadcast');
})
#增加监听器数量 channel 是事件发射器
channel.setMaxListeners(50);
#创建一个错误接听器
var server = net.createServer();
server.on('connection',function(client){
  var id = client.remoteAddress + ':' + client.remotePort;
  #连接时
  console.log('connect success');
  channel.emit('join',id,client);
  client.on('data',function(data){
    data = data.toString();
    if(data == "shutdown\r\n"){
      channel.emit('shutdown');
    }
    channel.emit('broadcast',id,data);
  });
  #用户断开连接时发出leave事件
  client.on('close',function(){
    channel.emit('leave',id);
  });
});
server.listen(8888);

用匿名函数保留全局变量的值

/*异步 color在不断变化 */
function asyncFunction(callback){
  setTimeout(callback,200);
}
var color = 'blue';
asyncFunction(function(){
  console.log('no function is color ' + color);
});
/*
* 解决方法
* 用javascript闭包可以“冻结”color的值
* 对asyncFunction的调用被封装到以color为参数的匿名函数中
*/
(function(color){
  asyncFunction(function(){
    console.log("function is color " + color);
  });
})(color);
var color = 'green';

1.3 异步逻辑顺序化

用Nimble的流程控制

#安装Nimble
npm install nimble

Nimble工具实现串行

var flow = require('nimble');
flow.series([
    function(callback){
        setTimeout(function(){
            console.log('I exec first.');
            callback();
        },1000);
    },
    function(callback){
        setTimeout(function(){
            console.log('I exec second.');
            callback();
        },500);
    },
    function(callback){
        setTimeout(function(){
            console.log('I exec third.');
            callback();
        },100);
    }
]);

1.3.2 实现串行化流程控制
将预先需要按流程执行的任务添加到数组中

/*
* 串行执行
* 并行下载后 串行执行归档
*/

var flow = require('nimble');
var exec = require('child_process').exec;

//下载文件辅助函数
function downloadNodeVersion(version,destination,callback){
    var url = "http://nodejs.org/dist/node-v" + version + ".tar.gz";
    var filepath = destination + '/' + version + '.tgz';
    exec('curl '+url+' > '+ filepath,callback);
}
//按照顺序执行串行化任务 series 串行的
flow.series([
    function(callback){
        //parallel 平行的 并列的
        flow.parallel([
            function(callback){
                console.log('Downloading Node v0.4.6....');
                downloadNodeVersion('0.4.6','/tmp',callback);
            },
            function(callback){
                console.log('Downloading Node v0.4.7....');
                downloadNodeVersion('0.4.7','/tmp',callback);
            }
        ],callback);
    },
    function(callback){
        //创建递归文件
        console.log('Creating archive of download files');
        exec('tar cvf node_distros.tar /tmp/0.4.6.tgz /tmp/0.4.7.tgz',
        function(error,stdout,stderr){
            console.log('All done!');
            callback();
        }
    )
}
]);

1.3.3 并行流程控制

/*
* 并行化流程控制
* 计算文件中单词出现的次数
*/
var fs = require('fs');
var completedTakes = 0;
var takes = [];
var wordCounts = {};
var fileDir = './text';

//所有的任务都完成后
function checkIfComplate(){
  completedTakes++;
  if(completedTakes == takes.length){
    for(var index in wordCounts){
      console.log(index + ': '+wordCounts[index]);
    }
  }
}

//计算文件中出现的单词数
function countWordsInText(text){
  var words = text.toString().toLowerCase().split(' ');
  console.log(words);

    for(var index in words){
      word = words[index];
      if(word){
        wordCounts[word] = (wordCounts[word])?wordCounts[word]+1:1;
      }

    }
}

//读取文件
fs.readdir(fileDir,function(err,files){
  if(err) throw err;
  for(var index in files){
    var take = (function(file){
      return function(){
        fs.readFile(file,function(err,text){
          if(err) throw err;
          countWordsInText(text);
          checkIfComplate();
        });
      }
    })(fileDir +'/'+ files[index]);
    //加入排序中
    takes.push(take);
  }
  for(var index in takes){
    takes[index]();
  }
});

水平一般,能力有限。随手记忆~~~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容