我有一个非常基本的脚本,我一直在添加的功能一点一点-几乎没有优化。
它应该通过X brands并为每个调用运行一个API调用(每个调用都有一个唯一的端点),然后将结果保存到CSV。
CSV部分工作得很好,虽然有点慢。(200 20文件约20秒)。
但是,当我将所有这些都封装在brands的一个循环中时,现在就超时了。默认情况下,它将运行2分钟,然后给我一个错误FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
我学会了附加--max_old_space_size=4000000来给它额外的内存(它也死了2GB)。在4GB时,我没有收到错误,但是我收到了Windows内存泄漏警告,所以很明显,我的脚本有问题。我觉得它在循环中循环,但不确定。
var http = require("https");
var qs = require("querystring");
var csvWriter = require('csv-write-stream');
var fs = require('fs');
var moment = require('moment');
let key = '';
var brands = ['REDACTED1','REDACTED2','REDACTED3','REDACTED4','REDACTED5','REDACTED6','REDACTED7','REDACTED8']
var dataRequest = function(token){
var date = new Date()-1; //Make it yesterday
var formattedDate = moment(date).format('YYYYMMDD');
var yesterdayDashes = moment(date).format('YYYY-MM-DD');
for (var k=0;k<=brands.length;k++){
var headers = [];
var csvBody = [];
var csvContent = "data:text/csv;charset=utf-8,";
var options = {
"method": "GET",
"hostname": "REDACTED",
"port": "443",
"path": "REDACTED/"+brands[k]+"/"+yesterdayDashes+"?REDACTED&access_token="+token,
"headers": {
"authentication": "Bearer "+token,
"content-type": "application/json",
"cache-control": "no-cache"
}
}
var req = http.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
var body = Buffer.concat(chunks);
var object = JSON.parse(body);
var writer = csvWriter({
headers: ["REDACTED1", "REDACTED2", "REDACTED3", "REDACTED4", "REDACTED5", "REDACTED6", "REDACTED7", "REDACTED8", "REDACTED9"]
})
writer.pipe(fs.createWriteStream(brands[k] +'_' +formattedDate +'_DEMOGRAPHIC.csv'))
for (var i=0;i<object.length; i++){
writer.write([
object[i].field1.REDACTED1,
moment(object[i].optin.REDACTED2).format('YYYYMMDD HHMMSS'),
object[i].field2.REDACTED1,
object[i].field2.REDACTED2,
object[i].field2.REDACTED3,
object[i].field2.REDACTED4,
object[i].field2.REDACTED5,
object[i].field3.REDACTED6,
object[i].field3.REDACTED7
])
}
writer.end()
});
});
req.end();
}
}
var authToken = function(){
var form = qs.stringify({
grant_type: 'client_credentials',
client_credentials: 'client_id:client_secret',
client_id: 'cdg-trusted-client',
client_secret: 'REDACTED'
})
var options = {
"method": "POST",
"hostname": "REDACTED3",
"port": null,
"path": "REDACTED3",
"headers": {
"Content-Type": "application/x-www-form-urlencoded",
"cache-control": "no-cache"
}
};
var req = http.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
var body = Buffer.concat(chunks);
var json = JSON.parse(body);
key = json['access_token'];
});
});
req.write(form);
req.end();
dataRequest(key);
}
authToken();我删除了敏感信息,但所有的逻辑都保留了下来。这是一个我很快就拼凑在一起的脚本,但老实说,我并没有看到它需要这么多内存的任何理由。我想这可能是无限循环,但是直接测试节点内的每个循环,我没有问题。
流开始获取承载令牌一次,然后将其传递给函数以获取数据。
当我讨论将其放入CodeReview中时,这段代码在技术上根本不起作用。
修改第一个循环的Update现在会立即输出unidentified CSV,而不会完全输出任何其他内容。但是,console.log(brands[k])正在输出适当的文件。
更新2
我的JS调试版本使console.log()无处不在,我注意到当我进入http.request init之后,brandsk突然变得没有定义。我想这可能是因为它没有传递到函数中而引起的?
更新3
我的undefined问题是由缺少分号引起的,它提前结束了for循环。我已经纠正了它,但现在我有一个最大的堆栈跟踪问题再次。
我的问题上下文现在似乎是“如何使这个for不运行异步?”
发布于 2017-07-26 21:22:41
这是您的问题:for (var k=0;k=brands.length;k++){,您使用了操作符=,它是赋值操作符,并将品牌的长度放入变量k中,而不是检查k是否仍然更小的<操作符,然后是brands.length。
所发生的情况是,在循环中测试的表达式是数字8(品牌数组的长度),它总是保持为8,所以您将进入一个无限循环。
注意,使用布尔表达式,与0不同的任何值都表示值true,而0表示false。
这是关于无限循环问题,还请注意,在将令牌传递给dataRequest函数时,代码还有另一个问题。
问题在于您试图在发送请求的req.end()之后立即传递它。
此时,响应仍然不存在,res.on("end", ...的回调函数仍未执行。基本上,您是将未定义的信息传递给dataRequest函数,这将导致您的第二个错误。只需将对dataRequest的调用移动到end回调中,如下所示:
res.on("end", function () {
var body = Buffer.concat(chunks);
var json = JSON.parse(body);
key = json['access_token'];
dataRequest(key);
});发布于 2017-07-26 23:15:23
var http = require("https");
var qs = require("querystring");
var csvWriter = require('csv-write-stream');
var fs = require('fs');
var moment = require('moment');
let key = '';
var brands = ['REDACTED1','REDACTED2','REDACTED3','REDACTED4','REDACTED5','REDACTED6','REDACTED7','REDACTED8']
var dataRequest = function(token, client){
var date = new Date()-1; //Make it yesterday
var formattedDate = moment(date).format('YYYYMMDD');
var yesterdayDashes = moment(date).format('YYYY-MM-DD');
var headers = [];
var csvBody = [];
var csvContent = "data:text/csv;charset=utf-8,";
var options = {
"method": "GET",
"hostname": "REDACTED",
"port": "443",
"path": "REDACTED/"+client+"/"+yesterdayDashes+"?REDACTED&access_token="+token,
"headers": {
"authentication": "Bearer "+token,
"content-type": "application/json",
"cache-control": "no-cache"
}
}; // <--- This was the culprit
var req = http.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
var body = Buffer.concat(chunks);
var object = JSON.parse(body);
var writer = csvWriter({
headers: ["REDACTED1", "REDACTED2", "REDACTED3", "REDACTED4", "REDACTED5", "REDACTED6", "REDACTED7", "REDACTED8", "REDACTED9"]
})
writer.pipe(fs.createWriteStream(client +'_' +formattedDate +'_DEMOGRAPHIC.csv'))
for (var i=0;i<object.length; i++){
writer.write([
object[i].field1.REDACTED1,
moment(object[i].optin.REDACTED2).format('YYYYMMDD HHMMSS'),
object[i].field2.REDACTED1,
object[i].field2.REDACTED2,
object[i].field2.REDACTED3,
object[i].field2.REDACTED4,
object[i].field2.REDACTED5,
object[i].field3.REDACTED6,
object[i].field3.REDACTED7
])
}
writer.end()
});
});
req.end();
}
}
var authToken = function(){
var form = qs.stringify({
grant_type: 'client_credentials',
client_credentials: 'client_id:client_secret',
client_id: 'cdg-trusted-client',
client_secret: 'REDACTED'
})
var options = {
"method": "POST",
"hostname": "REDACTED3",
"port": null,
"path": "REDACTED3",
"headers": {
"Content-Type": "application/x-www-form-urlencoded",
"cache-control": "no-cache"
}
};
var req = http.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
var body = Buffer.concat(chunks);
var json = JSON.parse(body);
key = json['access_token'];
for (var k=0;k<=brands.length;k++){
var client = brands[k];
dataRequest(key, client);
});
});
req.write(form);
req.end();
}
authToken();最后,正如上面所述,我在使用k = x时遇到了问题,一旦我将它修改为k < x,我已经对代码进行了多次更改,导致了上面的更新。除了k = x,我在上面的位置上有一个分号,这破坏了我的for。
我还选择了每个brand启动一个呼叫,而不是在品牌内发起它。这个脚本现在运行得很好。
我增加了一个次要的答案,以避免夸大问题,并在最后显示整个工作代码。
https://stackoverflow.com/questions/45337444
复制相似问题