nodejs使用 eventproxy 控制并发

更新日期: 2019-05-13阅读: 2.2k标签: 并发

目标

爬取 CNode社区首页的标题和详情页的第一条评论,以及评论的作者,作者积分,最后以json格式打印


步骤

注意:很多网站有并发连接数的限制,所以当请求发送太快的时候会导致返回值为空或报错。  

安装依赖 express superagent cheerio eventproxy

$ npm install express superagent cheerio eventproxy --save

新建app.js 抓取所有的url

// 引入依赖
var express = require('express');
var eventproxy = require('eventproxy');
var superagent = require('superagent');
var cheerio = require('cheerio');

var app = express();

// url 模块是 Node.js 标准库里面的
var url = require('url');

var cnodeUrl = 'https://cnodejs.org/';

app.get('/', function(req, res, next) {
    // 用 superagent 去抓取 https://cnodejs.org/ 的内容
    superagent.get(cnodeUrl)
        .end(function(err, sres) {
            if (err) {
                return next(err);
            }
            // sres.text 里面存储着网页的 html 内容,将它传给 cheerio.load 之后,就可以得到一个实现了 jquery 接口的变量,我们习惯性地将它命名为 `$`
            // 剩下就都是 jquery 的内容了
            var $ = cheerio.load(sres.text);
            
            var topicUrls = [];
            // 获取所有链接
            $('#topic_list .topic_title').each(function(index, elem) {
                var $element = $(elem);

                // url.resolve 来自动推断出完整 url
                var href = url.resolve(cnodeUrl, $element.attr('href'));
                topicUrls.push(href);
            });

            res.send(topicUrls);
        });
});

app.listen(3000, function (req, res) {
    console.log('app is running at port 3000');
});

运行node app.js


eventproxy

var ep = new eventproxy();
ep.all('data1_event', 'data2_event', 'data3_event', function (data1, data2, data3) {
  var html = fuck(data1, data2, data3);
  render(html);
});

$.get('http://data1_source', function (data) {
  ep.emit('data1_event', data);
  });

$.get('http://data2_source', function (data) {
  ep.emit('data2_event', data);
  });

$.get('http://data3_source', function (data) {
  ep.emit('data3_event', data);
  });

ep.all('data1_event', 'data2_event', 'data3_event', function (data1, data2, data3) {});这一句,监听了三个事件,分别是 data1_event, data2_event, data3_event,每次当一个源的数据抓取完成时,就通过 ep.emit() 来告诉 ep 自己,某某事件已经完成了。

当三个事件未同时完成时,ep.emit() 调用之后不会做任何事;当三个事件都完成的时候,就会调用末尾的那个回调函数,来对它们进行统一处理。


详细

// 引入依赖
var express = require('express');
var eventproxy = require('eventproxy');
var superagent = require('superagent');
var cheerio = require('cheerio');
// url 模块是 Node.js 标准库里面的
var url = require('url');

var app = express();
var ep = new eventproxy(); // 得到一个 eventproxy 的实例


var cnodeUrl = 'https://cnodejs.org/';

app.get('/', function(req, res, next) {
    // 用 superagent 去抓取 https://cnodejs.org/ 的内容
    superagent.get(cnodeUrl)
        .end(function(err, sres) {
            if (err) {
                return next(err);
            }
            // sres.text 里面存储着网页的 html 内容,将它传给 cheerio.load 之后,就可以得到一个实现了 jquery 接口的变量,我们习惯性地将它命名为 `$`
            // 剩下就都是 jquery 的内容了
            var $ = cheerio.load(sres.text);
            
            var topicUrls = [];
            // 获取所有链接
            $('#topic_list .topic_title').each(function(index, elem) {
                var $element = $(elem);

                // url.resolve 来自动推断出完整 url
                var href = url.resolve(cnodeUrl, $element.attr('href'));
                topicUrls.push(href);
            });

            // 命令 ep 重复监听 topicUrls.length 次(在这里也就是 40 次) `topic_html` 事件再行动
            ep.after('topic_html', topicUrls.length, function(topics) {
                // topics 是个数组,包含了 40 次 ep.emit('topic_html', pair) 中的那 40 个 pair

                topics = topics.map(function(topicpair) {
                    var topicUrl = topicpair[0];
                    var topicHtml = topicpair[1];
                    var $ = cheerio.load(topicHtml);
                    return ({
                        title: $('.topic_full_title').text().trim(),
                        href: topicUrl,
                        comment: $('.reply_content').eq(0).text().trim(),
                    });
                });
                
                res.send(topics);
            })

            topicUrls.forEach(function(topicUrl) {
                superagent.get(topicUrl)
                    .end(function(uerr, ures) {
                        console.log('success:' + topicUrl);
                        ep.emit('topic_html', [topicUrl, ures.text]);
                    });
            });
        });
});

app.listen(3000, function (req, res) {
    console.log('app is running at port 3000');
});

链接: https://www.fly63.com/article/detial/3676

PHP和Redis实现在高并发下的抢购及秒杀功能示例详解

抢购、秒杀是平常很常见的场景,面试的时候面试官也经常会问到,比如问你淘宝中的抢购秒杀是怎么实现的等等。抢购、秒杀实现很简单,但是有些问题需要解决,主要针对两个问题:

说一说数据库的并发控制

最近在看Elasticsearch时看到了并发控制,由此看到了新的并发控制方式。不得不说Elasticsearch相较于关系型数据库就是两种理论建立的数据存储体系,当然它们在并发控制上也相差甚远,各有千秋。

PHP-高并发和大流量的解决方案

在互联网时代,并发,高并发通常是指并发访问。也就是在某个时间点,有多少个访问同时到来。 高并发架构相关概念QPS (每秒查询率) : 每秒钟请求或者查询的数量,在互联网领域,指每秒响应请求数

处理高并发的一般思路

今天看见有人聊目前系统有2亿的PV,该如何优化?当我看到这个话题的时候,突然在想自己工作中也遇到了不少高并发的场景了,所以即兴发挥,在这里简单总结和分享下,欢迎指正和补充。

PHP 并发场景的几种解决方案

在秒杀,抢购等并发场景下,可能会出现超卖的现象,在PHP语言中并没有原生提供并发的解决方案,因此就需要借助其他方式来实现并发控制。列出常见的解决方案有:

并发编程三要素:原子性,有序性,可见性

并发编程三要素:原子性: 一个不可再被分割的颗粒。原子性指的是一个或多个操作要么全部执行成功要么全部执行失败。有序性: 程序执行的顺序按照代码的先后顺序执行。(处理器可能会对指令进行重排序)

通过Iterator控制Promise.all的并发数

异步是 js 一个非常重要的特性,但很多时候,我们不仅仅想让一系列任务并行执行,还想要控制同时执行的并发数,尤其是在针对操作有限资源的异步任务,比如文件句柄,网络端口等等。

nodejs如何解决高并发?

Node可以在不新增额外线程的情况下,依然可以对任务进行并发处理 —— Node.js是单线程的。它通过事件循环(event loop)来实现并发操作,对此,我们应该要充分利用这一点 —— 尽可能的避免阻塞操作

如何利用 JavaScript 实现并发控制

在开发过程中,有时会遇到需要控制任务并发执行数量的需求。例如一个爬虫程序,可以通过限制其并发任务数量来降低请求频率,从而避免由于请求过于频繁被封禁问题的发生。

JavaScript 中如何实现并发控制?

在日常开发过程中,你可能会遇到并发控制的场景,比如控制请求并发数。那么在 JavaScript 中如何实现并发控制呢?在回答这个问题之前,我们来简单介绍一下并发控制。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!