Node.js并发编程eventproxy详解与代码示例

80 阅读9分钟

更多技术信息请关注我公众号:CTO Plus,获取更多。

图片.png 原文:Node.js并发编程eventproxy详解与代码示例

图片

EventProxy 仅仅是一个 Node.js 的很轻量的基于事件的异步编程工具,它的主要功能是协调多个异步操作的执行顺序和结果的处理,它可以帮助我们更好地控制异步流程。EventProxy 的核心思想是事件监听和发布订阅模式,通过监听多个事件的触发情况来控制异步操作的执行顺序和结果的处理。

图片

在本文中,我们将深入了解如何使用eventproxy模块来控制并发,下一篇将介绍async的并发控制功能。让我们开始吧!

EventProxy的特点

能够带来一种事件式编程的思维变化。有几个特点:

  1. 利用事件机制解耦复杂业务逻辑。

  2. 解决回调地狱:移除被广为诟病的深度callback嵌套问题,通过事件监听和发布订阅模式,避免了回调地狱的问题。

  3. 将串行等待变成并行等待,提升多异步协作场景下的执行效率。

  4. 错误处理:友好的Error handling,EventProxy 可以处理异步操作中的错误,避免程序崩溃。

  5. 无平台依赖,适合前后端,能用于浏览器和Node.js。

  6. 兼容CMD,AMD以及CommonJS模块环境。

  7. 简单易用:EventProxy 的 API 简洁明了,使用起来非常方便。

  8. 支持并发:EventProxy 可以同时处理多个异步操作,并且可以控制它们的执行顺序。

eventproxy模块的应用场景和底层原理

eventproxy模块的应用场景

eventproxy模块的主要应用场景是处理多个异步操作的结果,将这些结果整合后再进行下一步操作。例如,在 Node.js 中发起多个网络请求,等所有请求都完成后再进行下一步操作。

eventproxy模块的底层原理

eventproxy模块的底层原理是基于事件监听器的异步编程解决方案。通过将多个异步操作转化为事件,再通过事件监听器的方式等待这些事件完成,从而实现多个异步操作的整合和处理。

安装模块

首先,我们需要安装eventproxy模块。可以使用npm(Node.js包管理器)来安装这个模块。打开终端并运行以下命令:

npm install eventproxy

这将安装最新版本的eventproxy模块。

 

示例1:EventProxy实现多个异步操作的协调

const eventproxy = require('eventproxy');
const fs = require('node:fs');
// 等价
//const fs = require('fs');

// 第一步:得到一个 eventproxy 实例
const ep = new eventproxy();

// 第二步:告诉它要监听哪些事件,并给它一个回调函数。ep.all('event1', 'event2', function (result1, result2) {})
// 通过 all 方法来监听多个事件的触发情况
// 当file1和file2 两个事件未同时完成时,ep.emit() 调用之后不会做任何事;当两个事件都完成的时候,就会调用末尾的回调函数,来对它们进行统一处理。
ep.all('file1', 'file2', function (data1, data2) {
    console.log(data1, data2);
});

fs.readFile('package-lock.json', 'utf-8', function (err,data) {
    // 此处的参数1:file1 要和 ep.all中的参数保持一致
    ep.emit('file1', data);
});

fs.readFile('node_modules/htmlparser2/package.json', 'utf8', function (err, data) {
    // 第三步:在适当的时候触发 ep.emit('event_name', eventData)
    //通过 emit 方法来触发事件  当文件读取完毕,就通过emit来告诉ep文件读取操作完毕。
    ep.emit('file2', data);
});

在上面的例子中,我们通过 EventProxy 的 all 方法来监听两个事件 file1和 file2 的触发情况。当两个事件都触发时,就会执行回调函数,并且把 file1 和 file2 的数据传递给回调函数。

在异步操作中,我们通过 emit 方法来触发事件,通过 all 方法来监听多个事件的触发情况。这样就可以控制异步操作的执行顺序和结果的处理。

示例2:EventProxy实现多个异步操作请求页面数据

接下来,我们将使用eventproxy模块来控制并发。在项目pro3的根目录中,创建一个名为eventproxy_app.js的文件,并添加以下内容:

const eventproxy = require('eventproxy');
const superagent = require('superagent');
const cheerio = require('cheerio');
const url = require('node:url');  // Nodejs内置模块

// eventproxy 的实例
const ep = new eventproxy();

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

// 使用`ep.after()`方法来控制并发  命令 ep 重复监听 3 次 `topic_html` 事件再行动
ep.after('topic_html', 3, (topics) => {
  topics = topics.map((topicPair) => {
    const topicUrl = topicPair[0];
    const topicHtml = topicPair[1];
    const $ = cheerio.load(topicHtml);
    return ({
      title: $('.topic_full_title').text().trim(),
      href: topicUrl,
      comment1: $('.reply_content').eq(0).text().trim(),
    });
  });
  console.log('final:');
  console.log(topics);
});

superagent.get(cnodeUrl)
  .end((err, res) => {
    if (err) {
      console.log(`请求失败,错误信息:${err}`);
      return;
    }
    const topicUrls = [];
    const $ = cheerio.load(res.text);
    $('#topic_list .topic_title').each((idx, element) => {
      const $element = $(element);
      const href = $element.attr('href');
      topicUrls.push(href);

      // 可以获取完整的URL地址
      const href2 = url.resolve(cnodeUrl, href);
      console.log(href2);
    });

    console.log(topicUrls.length, topicUrls);

    topicUrls.forEach((topicUrl) => {
      superagent.get(`${cnodeUrl}${topicUrl}`)
        .end((err, res) => {
          console.log(`fetch ${topicUrl} successful`);
          ep.emit('topic_html', [topicUrl, res.text]);
        });
    });
  });

在这个代码中,我们首先引入了eventproxysuperagentcheerio模块,并创建了一个eventproxy实例。然后,我们使用ep.after()方法来控制并发,它将在所有异步任务完成后调用回调函数。在这个例子中,我们需要获取3个主题的HTML响应,所以我们设置了ep.after('topic_html', 3, callback)。在每个异步任务完成后,我们使用ep.emit()方法来发送一个事件,并将结果传递给回调函数。

 

在主函数中,我们首先使用superagent模块发出HTTP请求,并使用cheerio模块解析HTML响应,获取所有主题的URL。然后,我们使用forEach()方法来遍历所有主题的URL,并使用superagent模块发出HTTP请求获取每个主题的HTML响应。在每个异步任务完成后,我们使用ep.emit()方法来发送一个事件,并将结果传递给回调函数。

 

最后,我们在回调函数中使用cheerio模块解析HTML响应,并将结果打印到控制台上。

 

现在我们已经完成了使用eventproxy模块控制并发的应用程序的编写。在终端中,进入项目的根目录并运行以下命令:

 

node eventproxy_app.js

 

这将发出HTTP请求并将结果打印到控制台上。

图片

Node.js异步流程控制工具EventProxy、Async 和 Promise对比分析

 

Node.js 中常用的异步流程控制工具包括EventProxy、Async 和 Promise。可以根据实际场景和需求选择适当的工具。EventProxy 适用于事件驱动的场景,Async 适用于大量异步任务的场景,Promise适用于需要处理异步操作的场景。它们各有特点和适用场景:

 

1. EventProxy

 

EventProxy 是一个轻量级的事件代理库,可以实现事件的串行和并行处理,避免回调地狱。EventProxy 的特点如下:

 

可以通过 on 和 once 方法监听事件,通过 emit 方法触发事件。

可以通过 after 和 all 方法实现串行和并行事件处理。

可以通过 fail 方法处理错误事件,避免程序崩溃。

 

EventProxy 适用于事件驱动的场景,例如爬虫、数据抓取等。

 

2. Async

 

Async 是一个流程控制库,提供了一系列异步函数和控制流程函数,可以实现异步流程的串行和并行处理。Async 的特点如下:

 

可以通过一系列异步函数实现异步流程的串行和并行处理。

可以通过 waterfall 和 series 方法实现异步流程的串行处理。

可以通过 parallel 和 map 方法实现异步流程的并行处理。

 

Async 适用于需要处理大量异步任务的场景,例如文件读写、数据库操作等。

 

3. Promise

Promise 是一种异步编程模型,通过Promise 对象封装异步操作,可以实现链式调用和错误处理。Promise 的特点如下:

可以通过 Promise 对象封装异步操作,实现链式调用和错误处理。

可以通过 then 和 catch 方法处理异步操作的成功和失败。

可以通过 Promise.all 方法实现多个异步操作的并行处理。

Promise 适用于需要处理异步操作的场景,例如网络请求、文件读写等。

结论

EventProxy 是一个非常实用的异步编程工具,它可以帮助我们协调多个异步操作的执行顺序和结果的处理,避免了回调地狱的问题。通过事件监听和发布订阅模式,我们可以更加方便地控制异步操作的执行顺序和结果的处理。

github地址:github.com/JacksonTian…

更多精彩,关注我公号 ,一起学习、成长 图片.png

Node.js系列文章推荐阅读: