任务:我从服务器(不是我的)收集地理数据。为此,我形成了对特定坐标区间的请求,并在 for 循环中向服务器发送请求。我将答案写入文件,这样服务器就不会禁止我通过 tor-control 更改 ip 地址。等待响应是使用 promise 实现的。这是理想的。事实上(根据控制台中的日志判断),数据是随机发送的。告诉我哪里走错了。
for (var i = xMin; i <= xMax; i++) {
for (var k = yMin; k <= yMax; k++) {
var swp = swPoint(k, i);
var nep = nePoint(k, i);
var llsw = pointToLatLong(swp[0], swp[1]);
var llne = pointToLatLong(nep[0], nep[1]);
var datatosend = 'fromlat=' + llsw[0].toString() + 'tolat=' + llne[0].toString() + 'fromlng=' + llsw[1].toString() + 'tolng' + llne[1].toString();
currX = k;
currY = i;
filename = "json/" + currX.toString() + "_" + currY.toString() + "_" + zoom.toString() + ".json";
options.body = datatosend;
console.log(filename);
GetData(options)
.then(body =>{
return WriteToFile(body, filename);
})
.then(() =>{
return GetNewCircuit();
})
.then(() =>{
console.log('Step finished');
})
}
}
从日志来看,原来是在没有等到前面的操作完成的情况下,冲了4次循环。
控制台日志文本:
json/0_0_1.json
json/1_0_1.json
json/0_1_1.json
json/1_1_1.json
Get response
json/1_1_1.json
Circuit changed
Step finished
Get response
json/1_1_1.json
Circuit changed
Step finished
Get response
json/1_1_1.json
Circuit changed
Step finished
Get response
json/1_1_1.json
Circuit changed
Step finished
调用方法:
function GetNewCircuit(){
return new promise(function(resolve, reject){
new_identity('127.0.0.1', 9051, cookie, function(err){
if(!err){
console.log('Circuit changed');
resolve()
} else{
console.log(err);
reject(err);
}
});
});
}
function GetData(reqOptions){
return new promise(function(resolve, reject){
request(reqOptions, function(error,response,body){
if(!error && response.statusCode == 200){
console.log('Get response');
resolve(body);
}
else{
reject(error);
}
});
});
}
function WriteToFile(dataToWrite, fileToWrite){
return new promise(function(resolve, reject) {
fs.writeFile(fileToWrite, dataToWrite, function(err) {
if(!err){
console.log(fileToWrite);
resolve();
}
else{
reject(err);
}
});
});
}
我刚刚开始熟悉js,所以如果除了答案之外,您还建议在哪里以及如何最好地结识,我只会很高兴。
在这段代码中,我同时看到了新手 javascript 开发人员面临的两个主要问题(共三个)。
问题一——对异步的误解。
当然,循环不会等到异步操作的结果返回后才可以循环。
想象一下,您有四只过度活跃的院子梗,您连续向它们扔了四个球。他们将以什么顺序将它们带回来?是的,鬼知道。
而Promise.then里面是回调,只是写的更方便而已。
该怎么办?
Don't:
第一个想到的方案,但是还是等第一个操作结束,然后在下一次迭代的时候增加循环计数器,开始下一个操作。但是通过这样做,您只是将异步操作转换为同步操作,并失去了异步带来的所有收益。
需要:
理解这段代码的主要问题不是异步,而是你不理解闭包。好吧,也就是说,您的控制台
json/1_1_1.json多次出现故障是否困扰您?问题二:
对js中作用域的误解,它们也是闭包。关于循环中变量值丢失的问题是中层开发人员面试中排名第一的问题,如果不回答,对话可能会被关闭。在这个资源上,这个问题以不同的形式出现,每周出现几次。例如,在这里它得到了详细的回答(真的没有提到 es6 中的块作用域)。
那么,也就是说,您的代码中错误的核心看起来像这样:
setTimeout这里 - 作为最简单的异步操作的例子。如果你不明白这里为什么会显示4乘4,那你就需要琢磨明白了。一定。简而言之,发生这种情况是因为 var 变量在 js 中的作用域是一个函数,而不是花括号。循环不形成单独的作用域,所有四次函数都将引用同一个变量 i,指向同一个内存区域。
好了,我都明白了,我还是要同步。
为了巧妙地管理管理许多异步请求的流程,有许多公共库,例如async,例如看
async.waterfall在循环中将承诺收集到一个数组中,然后使用 Promise.all 等待它们完成