node.js 学习笔记004:使用eventproxy控制并发
2016-04-17 16:24
756 查看
原文地址:lesson4 : 使用
在上一篇博客中达到了使用
当然,前提是已经引入了eventproxy
告诉它需要监听哪些事件,并提供回调函数
在适当的时候
后续可能会使用nodejs实现多生产者多消费者问题,敬请期待
不使用evenproxy的时候如何实现并发控制
比较经典的做法就是使用
如果使用
以上两个程序的原理几乎相同,eventproxy只是透明了计数器count的使用而已。
重复异步协作
此处以读取目录下的所有文件为例,在异步操作中,我们需要在所有异步调用结束后,执行某些操作。
2. 目标代码实现
结果示例
有些请求发生了错误,很有可能是并发请求数量太多遭到服务器拒绝服务,下一篇讲解如何控制并发连接数量。
eventproxy控制并发
在上一篇博客中达到了使用
superagent和
cheerio实现了简单网络爬虫的程序,现在的新需求是在上一个程序的基础上获取到每一个文章的第一条评论,这样难度就稍稍有些增加了
一、安装eventproxy
eventproxy是
nodejs中控制并发的一大利器
eventproxy在
github:https://github.com/JacksonTian/eventproxy
npm install eventproxy --save
二、使用eventproxy的步骤
创建eventproxy对象var ep=new eventproxy();
当然,前提是已经引入了eventproxy
var eventproxy=require("eventproxy");
告诉它需要监听哪些事件,并提供回调函数
ep.all('event_name',function(result){ });
在适当的时候
ep.emit('event_name',data);
三、eventproxy实现并发的原理
线程并发实际上是非常复杂的一个东西,它需要考虑到相当多的因素,比如线程间通信、死锁等,在这里则暂且都不考虑后续可能会使用nodejs实现多生产者多消费者问题,敬请期待
不使用evenproxy的时候如何实现并发控制
比较经典的做法就是使用
计数器控制并发,比如一共有3个并发线程,希望3个并发线程都完成之后才进行下一步操作,那么可以这么做
var count=0; var result={}; $.get("http://example.com/1.html",function(data){ result.data1=data; count++; handler(); }); $.get("http://example.com/2.html",function(data){ result.data2=data; count++; handler(); }); $.get("http://example.com/3.html",function(data){ result.data3=data; count++; handler(); }); function handler(){ if(count==3){ var html=getHtml(result); return html; } }
如果使用
eventproxy该如何做
var ep=new eventproxy(); ep.all('event1','event2','event3',function(data1,data2,data3){ var html=getHtml(data1,data2,data3); }); $.get("http://example.com/1.html",function(data){ ep.emit('event1',data); }); $.get("http://example.com/2.html",function(data){ ep.emit('event2',data); }); $.get("http://example.com/3.html",function(data){ ep.emit('event3',data); });
以上两个程序的原理几乎相同,eventproxy只是透明了计数器count的使用而已。
四、目标程序实现
目标程序的实现需要重点强调 重复异步协作 的使用方法,具体说明见链接。重复异步协作
此处以读取目录下的所有文件为例,在异步操作中,我们需要在所有异步调用结束后,执行某些操作。
var ep = new EventProxy(); ep.after('got_file', files.length, function (list) { // 在所有文件的异步执行结束后将被执行 // 所有文件的内容都存在list数组中 }); for (var i = 0; i < files.length; i++) { fs.readFile(files[i], 'utf-8', function (err, content) { // 触发结果事件 ep.emit('got_file', content); }); }
after方法适合重复的操作,比如读取10个文件,调用5次数据库等。将handler注册到N次相同事件的触发上。达到指定的触发数,handler将会被调用执行,每次触发的数据,将会按触发顺序,存为数组作为参数传入。
2. 目标代码实现
var express=require("express"); var superagent=require("superagent"); var cheerio=require("cheerio"); var url=require("url"); var eventproxy=require("eventproxy"); var app=express(); var baseUrl='https://cnodejs.org/'; function output(arr){ for(var i=0;i<arr.length;i++){ console.log(arr[i]); } } superagent.get(baseUrl).end(function(err,resp){ if(err){ return console.error(err); } var arr=[]; var $=cheerio.load(resp.text); $("#topic_list .topic_title").each(function(idx,element){ $element=$(element); var _url=url.resolve(baseUrl,$element.attr("href")); arr.push(_url); }); //验证得到的所有文章链接集合 output(arr); //接下来遍历arr,解析每一个页面中需要的信息 var ep=new eventproxy(); ep.after('destEvent',arr.length,function(topics){ topics=topics.map(function(topic){ var _url=topic[0]; var message=topic[1]; var $=cheerio.load(message); return { title:$(".topic_full_title").text().trim(), href:_url, firstcomment:$("#reply1 .markdown-text").text().trim() }; }); console.log("result :"); console.log(topics); }); arr.forEach(function(_url){ superagent.get(_url).end(function(err,mes){ if(err){ console.log("get \""+_url+"\" error !"+err); console.log("message info:"+JSON.stringify(mes)); } console.log('fetch '+_url+" succeful !"); ep.emit('destEvent',[_url,mes.text]); }); }); });
结果示例
{ title: '', href: 'https://cnodejs.org/topic/57108b8f0a1e9da252f1e347', firstcomment: '' }, { title: '', href: 'https://cnodejs.org/topic/571054ae8b5ce7be52adc019', firstcomment: '' }, { title: '', href: 'https://cnodejs.org/topic/570ce12704e7772f4eb639d6', firstcomment: '' }, { title: 'nodejs报错Cannot find module \'./lib/topologies/server\'', href: 'https://cnodejs.org/topic/571308a6434cfcfa52684ae2', firstcomment: '问题没有上下文大家看了,都没啥感觉啊, 让人摸不着头脑的感觉~' }, { title: '写了篇有关CSRF的博客,大家多批评~', href: 'https://cnodejs.org/topic/56c833f9d1e0945c614187e6', firstcomment: '做安全的么。。。' }, { title: '精华\n\n\n\n React-Native 客户端【v1.0.0-alpha2】【安卓已发布】【最后更新:2016.4.14】', href: 'https://cnodejs.org/topic/559bd1b91e5c761761468884', firstcomment: '不错,顶起' }, { title: '置顶\n\n\n\n cnode 社区也切换到 Let\'s encrypt 了', href: 'https://cnodejs.org/topic/5711f1816a2d2bda52de962a', firstcomment: 'ssllab 也拿到 A 了 https://www.ssllabs.com/ssltest/analyze.html?d=cnodejs.org' }, { title: '置顶\n\n\n\n 前端资源教程', href: 'https://cnodejs.org/topic/56ef3edd532839c33a99d00e', firstcomment: '感谢大神分享!\n来自酷炫的 CNodeMD' }, { title: '置顶\n\n\n\n 国内Nodejs 2015汇总', href: 'https://cnodejs.org/topic/5696e43e6272216e51bff67e', firstcomment: '桑大大,很赞�' }, { title: 'timer 的 unref 函数', href: 'https://cnodejs.org/topic/570924d294b38dcb3c09a7a0', firstcomment: '6666' }, { title: '一个基于NodeJs + ReactJs构建的轻量级博客系统', href: 'https://cnodejs.org/topic/57126364238ae0ac1e3a6a4f', firstcomment: '支持' }, { title: '精华\n\n\n\n cnode社区app客户端(Ionic2.0)', href: 'https://cnodejs.org/topic/57111863434cfcfa52684a8e', firstcomment: 'good job' }, { title: 'node的web应用被黑,求指导该如何处理', href: 'https://cnodejs.org/topic/5707198b8a612c5559d16d26', firstcomment: '你是什么服务器啊? 这么不安全?' } ]
有些请求发生了错误,很有可能是并发请求数量太多遭到服务器拒绝服务,下一篇讲解如何控制并发连接数量。
相关文章推荐
- 使用ruby部署工具mina快速部署nodejs应用教程
- Google官方支持的NodeJS访问API,提供后台登录授权
- 浅谈Nodejs观察者模式
- nodejs教程之环境安装及运行
- nodejs中的fiber(纤程)库详解
- 基于NodeJS的前后端分离的思考与实践(五)多终端适配
- 基于NodeJS的前后端分离的思考与实践(二)模版探索
- 实例详解Nodejs 保存 payload 发送过来的文件
- 我的NodeJs学习小结(一)
- Node.js 应用跑得更快 10 个技巧
- nodejs中实现sleep功能实例
- Nodejs异步回调的优雅处理方法
- Windows系统下使用Sublime搭建nodejs环境
- nodejs实现获取某宝商品分类
- nodejs简单实现中英文翻译
- Node.js插件的正确编写方式
- 使用upstart把nodejs应用封装为系统服务实例
- NodeJS Web应用监听sock文件实例
- Nodejs学习笔记之测试驱动
- Nodejs学习笔记之Stream模块