我正在使用zombie.js刮一个网站,我必须使用回调样式连接到每个网址.关键是我有一个urls数组,我需要使用异步函数处理每个url.这是我的第一个方法:
Array urls = {http..., http...}; function process_url(index) { if(index == urls.length) return; async_function(url, function() { ... //parse the url ... // Process the next url process_url(index++); } ); } process_url(0)
没有使用某人第三方nodejs库使用asyn功能作为同步功能或等待功能(wait.for,synchornized,mocha),这是我解决这个问题的方式,我不知道会是什么如果阵列太大,就会发生.调用下一个函数时,是否从内存中释放了函数?或者所有功能都在内存中直到结束?
有任何想法吗?
你的计划会奏效.我称之为"手动排序异步操作".
你正在做的通用版本看起来像这样:
function processItem(data, callback) { // do your async function here // for example, let's suppose it was an http request using the request module request(data, callback); } function processArray(array, fn) { var index = 0; function next() { if (index < array.length) { fn(array[index++], function(err, result) { // process error here if (err) return; // process result here next(); }); } } next(); } processArray(arr, processItem);
至于你的具体问题:
我不知道如果阵列太大会发生什么.调用下一个函数时,是否从内存中释放了函数?或者所有功能都在内存中直到结束?
Javascript中的内存在任何正在运行的代码不再引用时以及垃圾收集器有时间运行时发布.由于您在此处运行一系列异步操作,因此垃圾收集器很可能在等待异步操作的http响应时定期运行,因此可以清理内存.函数只是Javascript中的另一种类型的对象,它们像其他任何东西一样被垃圾收集.当它们不再通过运行代码引用时,它们有资格进行垃圾回收.
在您的特定代码中,因为您process_url()
只在异步回调中重新调用,所以没有堆栈构建(如在正常递归中).在process_url()
调用异步回调之前已经完成了先前的实例,并且在调用下一次迭代之前已经完成process_url()
.
通常,使用内置于当前版本的node.js中的promise并且是ES6 ECMAScript标准的一部分,可以更加轻松地管理和协调多个异步操作.在当前版本的node.js中使用promises不需要外部库.
有关使用promises而不使用promises对数组上的异步操作进行排序的许多不同技术的列表,请参阅:
如何同步一系列承诺?.
使用promises的第一步是"promisify"你的异步函数,以便它返回一个promise而不是回调.
function async_function_promise(url) { return new Promise(function(resolve, reject) { async_function(url, function(err, result) { if (err) { reject(err); } else { resolve(result); } }); }); }
现在,您有一个返回promises的函数版本.
如果你希望你的异步操作一次一个地进行,那么下一个操作就不会在前一个操作完成之前启动,那么通常的设计模式就是这样使用.reduce()
:
function process_urls(array) { return array.reduce(function(p, url) { return p.then(function(priorResult) { return async_function_promise(url); }); }, Promise.resolve()); }
然后,你可以像这样调用它:
var myArray = ["url1", "url2", ...]; process_urls(myArray).then(function(finalResult) { // all of them are done here }, function(err) { // error here });
还有一些Promise库具有一些有用的功能,使这种类型的编码更简单.我,我自己,使用Bluebird promise库.以下是使用Bluebird的代码的外观:
var Promise = require('bluebird'); var async_function_promise = Promise.promisify(async_function); function process_urls(array) { return Promise.map(array, async_function_promise, {concurrency: 1}); } process_urls(myArray).then(function(allResults) { // all of them are done here and allResults is an array of the results }, function(err) { // error here });
注意,您可以将concurrency
值更改为您想要的任何值.例如,如果将其增加到介于两者之间2
并且5
(取决于服务器实现如何最佳地优化),您可能会获得更快的端到端性能.