http.get 请求循环关闭问题(节点)
http.get request loop closure issue (Node)
我希望能够在命令行中输入 URL 的范围,并按照提供的顺序获取这些请求的结果。我研究了闭包来实现这一点,因为回调不会按顺序执行(更有可能是哪个响应最快)
for (var i = 2; i < process.argv.length; i++) {
(function(index) {
http.get(process.argv[index], function (response) {
response.pipe(bl(function (err, data) {
console.log(data.toString());
}));
});
})(i);
}
for 循环遍历参数。然后每次迭代调用 IIFE 匿名函数,后者又调用 get 请求等。
但是问题依旧,乱序执行。不符合用户要求的顺序。
我做错了什么?
如果你只是想按顺序记录结果,但你想并行地向 运行 发送请求,那么通常的解决方案是将结果收集到一个数组中,然后输出所有请求完成后的结果。
var count = process.argv.length - 2;
var results = new Array(count);
for (var i = 2; i < process.argv.length; i++) {
(function(index) {
http.get(process.argv[index], function (response) {
response.pipe(bl(function (err, data) {
results[index - 2] = data.toString();
--count;
if (count === 0) {
for (var j = 0; j < results.length; j++) {
console.log(results[j]);
}
}
}));
});
})(i);
}
当在此之前的所有请求都已完成而不是等待所有请求都完成时,这种蛮力方法也可以稍微智能一些以更快地输出结果。
另一种方法是对每个请求使用承诺,然后使用 Promise.all()
等待所有异步操作完成,Promise.all()
也会为您收集所有结果。
而且,像 Async 这样的 nodejs 库也有很多用于管理大量异步操作的功能。
如果你想序列化请求(只在前一个请求完成时才启动下一个请求),实际上会更简单一些。可以这样做:
function runAll() {
var index = 2;
function next() {
if (index < process.argv.length) {
http.get(process.argv[index], function (response) {
response.pipe(bl(function (err, data) {
console.log(data.toString());
++index;
next();
}));
});
}
}
next();
}
而且,这是一个使用 promises 的版本,运行 并行请求,但 returns 结果按顺序排列:
var Promise = require('bluebird');
function runAll() {
var promises = [];
for (var i = 2; i < process.argv.length; i++) {
promises.push(new Promise(function(resolve, reject) {
http.get(process.argv[index], function (response) {
response.pipe(bl(function (err, data) {
resolve(data.toString());
}));
});
}));
}
return Promise.all(promises);
}
runAll().then(function(resultArray) {
// resultArray contains an array of the results from all the operations, in order
for (var i = 0; i < resultArray.length; i++) {
console.log(resultArray[i]);
}
});
我希望能够在命令行中输入 URL 的范围,并按照提供的顺序获取这些请求的结果。我研究了闭包来实现这一点,因为回调不会按顺序执行(更有可能是哪个响应最快)
for (var i = 2; i < process.argv.length; i++) {
(function(index) {
http.get(process.argv[index], function (response) {
response.pipe(bl(function (err, data) {
console.log(data.toString());
}));
});
})(i);
}
for 循环遍历参数。然后每次迭代调用 IIFE 匿名函数,后者又调用 get 请求等。 但是问题依旧,乱序执行。不符合用户要求的顺序。
我做错了什么?
如果你只是想按顺序记录结果,但你想并行地向 运行 发送请求,那么通常的解决方案是将结果收集到一个数组中,然后输出所有请求完成后的结果。
var count = process.argv.length - 2;
var results = new Array(count);
for (var i = 2; i < process.argv.length; i++) {
(function(index) {
http.get(process.argv[index], function (response) {
response.pipe(bl(function (err, data) {
results[index - 2] = data.toString();
--count;
if (count === 0) {
for (var j = 0; j < results.length; j++) {
console.log(results[j]);
}
}
}));
});
})(i);
}
当在此之前的所有请求都已完成而不是等待所有请求都完成时,这种蛮力方法也可以稍微智能一些以更快地输出结果。
另一种方法是对每个请求使用承诺,然后使用 Promise.all()
等待所有异步操作完成,Promise.all()
也会为您收集所有结果。
而且,像 Async 这样的 nodejs 库也有很多用于管理大量异步操作的功能。
如果你想序列化请求(只在前一个请求完成时才启动下一个请求),实际上会更简单一些。可以这样做:
function runAll() {
var index = 2;
function next() {
if (index < process.argv.length) {
http.get(process.argv[index], function (response) {
response.pipe(bl(function (err, data) {
console.log(data.toString());
++index;
next();
}));
});
}
}
next();
}
而且,这是一个使用 promises 的版本,运行 并行请求,但 returns 结果按顺序排列:
var Promise = require('bluebird');
function runAll() {
var promises = [];
for (var i = 2; i < process.argv.length; i++) {
promises.push(new Promise(function(resolve, reject) {
http.get(process.argv[index], function (response) {
response.pipe(bl(function (err, data) {
resolve(data.toString());
}));
});
}));
}
return Promise.all(promises);
}
runAll().then(function(resultArray) {
// resultArray contains an array of the results from all the operations, in order
for (var i = 0; i < resultArray.length; i++) {
console.log(resultArray[i]);
}
});