Nodejs 从异步队列到中间件实现 —— (1)异步队列 asynclist

Nodejs 从异步队列到中间件实现 —— (1)异步队列 asynclist

之前给webjs的Router做了一个还算给力的东西:asynclist

基于小田的eventproxy,是用于并行处理一串的任务,比如说中间件。

因为是基于eventproxy,小问也把asynclist的使用方法做得和eventproxy相似,以便大家使用。

我们来看一个例子

//同步串行队列
var fs = require('fs');
function readBigFile () {
    for (var i = 0;i < 100;i++) fs.readFileSync('test.zip'); //3.2M
}
for (var i = 0;i < 10;i++) readBigFile();
console.log('Finished.');

//异步并行队列 var asynclist = require(‘asynclist’); var fs = require(‘fs’); function readBigFile () { for (var i = 0;i < 100;i++) fs.readFileSync(‘test.zip’); //3.2M tasks.trigger(true); }

var tasksList = []; for (var i = 0;i < 10;i++) tasksList.push(readBigFile);

var tasks = new asynclist(tasksList); tasks.assign(function () { console.log(‘Finished.’); }); console.log(‘Start’); tasks.run();

其中test.zip的大小为3.2M

相信以上两端代码的差别的效果大家不得而知。

如果大家还不知道asynclist究竟有什么实用性,那么小问再说一个应用场景:

我们要设计一个RSS Reader,于是我们就要把一系列的RSS Url存储起来,然后定时更新。

于是当我们需要对已记录的RSS Url进行更新的时候,我们要怎么做呢?

假设以下为需要请求的Urls

var rssUrls = [
  'http://www.a.com/rss',
  'http://www.b.com/feed',
  'http://www.c.com/rss',
  'http://www.d.com/feed',
  'http://www.e.com/rss',
  'http://www.f.com/feed'
]

Q:Node.js的http.get不就是异步的么? A:是的,我们需要它。

Q:eventproxy不就是已经可以在所有任务完成以后相应了么? A:是的,但是eventproxy是需要以下做法

var eventproxy = require('eventproxy').EventProxy;
var BufferHelper = require('bufferhelper');
var http = require('http');
var url = require('url');

var tasks = new eventproxy(); //生成任务队列 var taskList = rssUrl.map(function (url) { return function () { //通过BufferHelper对数据进行拼接 var bufferHelper = new BufferHelper(); http.get(url.parse(url), function (res) { res.on(‘data’, function (chunk) { bufferHelper.concat(chunk); }); res.on(‘end’, function () { var data = bufferHelper.toBuffer().toString(); //完成获取,向eventproxy汇报数据 tasks.trigger(‘success’, data); }); }); } }); tasks.after(‘success’, rssUrls.length, function (rows) { //当全部完成以后输出数据 console.log(rows); }); taskList.forEach(function (task) { task(); });

Q:哇。。小问写的好详细啊! A:啊哈哈哈,那是当然。。这就是asynclist的实现方式嘛,亲。。==

好吧,上面是一个小DEMO,但是大家要知道,不是所有的的东西都会异步执行回调函数,很有可能会直接执行,这样是没有办法达到并行处理的。

那小问是如何做到并行的呢?

其实嘛,有细心阅读我们社区文章和官方API文档的童鞋,相比已经知道了。对的,就是Node.js中对epoll的封装——Ticks机制。

在上面的代码中,你之需要改动一行就可以了。

......
taskList.forEach(function (task) {
    //task();
    process.nextTick(task);
});
......

当然,上面这些是否觉得不雅观?来看看asynclist吧。

asynclist默认需要传入一个包含Function的Array

var asynclist = require('asynclist');

var tasksList = rssUrl.map(function (url) { return function () { var bufferHelper = new BufferHelper(); http.get(url.parse(url), function (res) { res.on(‘data’, function (chunk) { bufferHelper.concat(chunk); }); res.on(‘end’, function () { var data = bufferHelper.toBuffer().toString(); tasks.trigger(‘success’, data); }); }); } }); var tasks = new asynclist(list); tasks.assign(function (rows) { console.log(rows); }); tasks.run();

还觉得上面的那个map很不好看?asynclist也封装好了。

var asynclist = require('asynclist');

var getter = asynclist.compile(function (url) {
    return function () {
	var bufferHelper = new BufferHelper();
	http.get(url.parse(url), function (res) {
	    res.on('data', function (chunk) {
	        bufferHelper.concat(chunk);
	    });
	    res.on('end', function () {
	        var data = bufferHelper.toBuffer().toString();
	        tasks.trigger('success', data);
	    });
	});
    }
});

var tasks = new getter(rssUrls);
tasks.assign(function (rows) {
    console.log(rows);
});
tasks.run();

以上代码中getter是新生成的一个lister,你之需要把这个getter到处”扔“就可以了。

如果还不满足,想要给tasks传入参数?可以。。 只要把你需要传入的参数传入run()方法就可以了,不过asynclist最多支持传入三个参数。 PS:当然这个只是半行代码的事情。。

OK,今天先到这里,明天继续第二章,webjs的中间件实现。(想必已经有人猜到了吧。。)


6 回复

Nodejs 从异步队列到中间件实现 —— (1)异步队列 asynclist

在本文中,我们将探讨如何使用 asynclist 来管理一系列异步任务,以及它与传统异步操作的区别。

引言

之前为 webjsRouter 开发了一个功能强大的工具:asynclist。该工具基于 eventproxy,用于并行处理一系列任务,例如中间件。

由于 asynclist 的使用方法与 eventproxy 相似,因此便于开发者快速上手。

示例代码

让我们通过几个示例来了解 asynclist 的使用方法及其优势。

同步串行队列

首先,我们看一个简单的同步串行队列的例子:

var fs = require('fs');
function readBigFile () {
    for (var i = 0; i < 100; i++) fs.readFileSync('test.zip'); // 3.2M
}
for (var i = 0; i < 10; i++) readBigFile();
console.log('Finished.');

在这个例子中,我们通过同步读取文件的方式,模拟了一个串行任务队列。这种方式会导致程序阻塞,直到所有任务完成。

异步并行队列

接下来,我们使用 asynclist 实现一个异步并行队列:

var asynclist = require('asynclist');
var fs = require('fs');
function readBigFile () {
    for (var i = 0; i < 100; i++) fs.readFileSync('test.zip'); // 3.2M
    tasks.trigger(true);
}

var tasksList = [];
for (var i = 0; i < 10; i++) tasksList.push(readBigFile);

var tasks = new asynclist(tasksList);
tasks.assign(function () {
    console.log('Finished.');
});
console.log('Start');
tasks.run();

在这个例子中,我们定义了一系列异步任务,并通过 asynclist 来管理这些任务。asynclist 会确保所有任务并发执行,并在所有任务完成后触发回调函数。

应用场景

假设我们需要设计一个 RSS 阅读器,并定期更新一系列 RSS URL 的内容。我们可以使用 asynclist 来管理这些任务:

var rssUrls = [
  'http://www.a.com/rss',
  'http://www.b.com/feed',
  'http://www.c.com/rss',
  'http://www.d.com/feed',
  'http://www.e.com/rss',
  'http://www.f.com/feed'
];

var asynclist = require('asynclist');

var getter = asynclist.compile(function (url) {
    return function () {
        var bufferHelper = new BufferHelper();
        http.get(url.parse(url), function (res) {
            res.on('data', function (chunk) {
                bufferHelper.concat(chunk);
            });
            res.on('end', function () {
                var data = bufferHelper.toBuffer().toString();
                tasks.trigger('success', data);
            });
        });
    }
});

var tasks = new getter(rssUrls);
tasks.assign(function (rows) {
    console.log(rows);
});
tasks.run();

在这个例子中,我们使用 asynclist 来并行处理多个 HTTP 请求,确保所有请求并发执行,并在所有请求完成后输出结果。

总结

通过 asynclist,我们可以更方便地管理和调度一系列异步任务,从而提高应用程序的性能和响应速度。希望这篇文章能够帮助你更好地理解和使用 asynclist


不错,小问很勤力啊!

第一段个例子有很大问题,你用readFileSync同步方法,10个并行读取没有效果的,等于10个串行读取。读一个文件要1秒的话,10个文件总归还是10秒。

oh yeah,老赵也来了

感觉可以改成10个下载文件. 10个同时下载和10个依次下载的区别. 这个由于网速的问题,差别应该就比较大了.

asynclist 是一个用于并行处理异步任务的工具,它可以帮助你更方便地管理一系列异步操作。以下是根据提供的内容整理出的 asynclist 的基本用法和示例代码。

示例代码

假设我们有一个 RSS 阅读器需要从多个 URL 获取数据。我们可以使用 asynclist 来并行处理这些请求:

const asynclist = require('asynclist');
const http = require('http');
const url = require('url');

// 需要请求的 URLs
var rssUrls = [
  'http://www.a.com/rss',
  'http://www.b.com/feed',
  'http://www.c.com/rss',
  'http://www.d.com/feed',
  'http://www.e.com/rss',
  'http://www.f.com/feed'
];

// 创建一个异步任务列表
var getter = asynclist.compile(function (u) {
    return function () {
        const bufferHelper = new BufferHelper();
        http.get(u, (res) => {
            res.on('data', (chunk) => {
                bufferHelper.concat(chunk);
            });
            res.on('end', () => {
                const data = bufferHelper.toBuffer().toString();
                this.trigger('success', data); // 使用 this 引用当前任务
            });
        });
    }
});

var tasks = new getter(rssUrls);
tasks.assign(function (rows) {
    console.log(rows);
});
tasks.run();

解释

  • asynclist.compile: 这个方法用来编译一个异步任务,返回一个新的任务生成器 getter。你可以传入一个函数,该函数将返回一个任务函数。
  • getter: 这是一个任务生成器,可以根据输入参数生成一个具体的任务。
  • tasks.assign: 这个方法用于定义任务完成后的行为。在这个例子中,它会在所有任务完成后打印出结果。
  • tasks.run: 开始执行任务列表中的所有任务。

总结

asynclist 提供了一种更简洁的方式来管理并行的异步任务。通过 asynclist.compile 编译任务,并通过 getter 生成具体任务,最后通过 tasks.run 执行这些任务。这种方式不仅提高了代码的可读性,还使代码更加模块化和易于维护。

回到顶部