你的方案会奏效。我称之为“手动排序异步操作”。
您正在执行的通用版本如下所示:
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 并且是 ES6 ECMAScript 标准的一部分的 Promise,管理和协调多个异步操作要容易得多。在当前版本的 node.js 中使用 Promise 不需要外部库。
有关使用 Promise 和不使用 Promise 对数组进行异步操作排序的多种不同技术的列表,请参阅:
How to synchronize a sequence of promises?.
使用 Promise 的第一步是“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);
}
});
});
}
现在,您有一个返回 Promise 的函数版本。
如果您希望一次执行一个异步操作,以便在前一个操作完成之前不会开始下一个操作,那么通常的设计模式是使用 .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 之间的某个值,您可能会获得更快的端到端性能(取决于服务器实现的最佳优化方式)。