我有一个基于 txt 文件内的值调用 API 的代码。 在每次 API 调用中,代码都会从响应 JSON 中提取一些信息并构造一个 csv。 每次完成对 API 的 HTTP get 调用时,我都会通过覆盖 csv 来使代码正常工作。但是,为了提高效率,我宁愿只写一次 csv。我当前的代码是这样的......
const fs = require("fs");
const https = require("https");
var text = ""
fs.readFile(filename, 'utf8', function(err, data) {
if (err) reject(error);
issns = data.split(/\r?\n/)
getPolicies(issns);
});
function getPolicies(issns){
for (let i = 0; i<issns.length; i++){
url = "some_api_url" + issns[i]
https.get(url, (resp) => {
let data = '';
resp.on('data', (chunk) => {
data += chunk;
});
resp.on('end', () => {
data = JSON.parse(data)
constructCSV(issns[i], data)
});
}).on("error", (err) => {
console.log("Error: " + err.message);
});
}
}
function constructCSV (issn, data){
// code to get some data from the json in parameter "data"
// ...
// ...
saveOutput()
}
function saveOutput(){
fs.writeFileSync(output_file_dir, text);
}
如前所述,我宁愿只调用 saveOutput() 一次,如果可能的话,在调用 getPolicies() 之后立即调用。然而,由于获取策略使用异步 http get,这会导致空白 csv 文件。
如果有人可以帮助我,我将非常感激!
嗯,看来你并不真正需要同步请求,而是检测所有请求何时完成。
一个简单的解决方案是跟踪最后一个请求,然后将其作为参数传递给
constructCSV
,然后在所有请求完成标志时调用saveOutput
:
// send last request flag
constructCSV(issns[i], data, i+1==issns.length)
//...
// write on the last request flag
function constructCSV (issn, data, done){
// code to get some data from the json in parameter "data"
// ...
// ...
if(done) saveOutput()
}
我制作了sync-request-curl,它可以帮助同步请求如果你想避免承诺或
async
/await
出于任何原因。
sync-request-curl 一个库,包含原始 sync-request 中的功能子集,但利用 node-libcurl 在 NodeJS 中获得更好的性能。
这是 GET 请求的基本用例:
// import request from 'sync-request-curl';
const request = require('sync-request-curl');
const response = request('GET', 'https://ipinfo.io/json');
console.log('Status Code:', response.statusCode);
console.log('body:', response.body.toString());
在性能方面,它与异步等效项(例如then-request)相当,不过,我再次建议如果可能的话,研究promises/
async
/await
。
具体到您的情况,当以同步方式完成时,它可能看起来像这样:
const fs = require("fs");
const request = require("sync-request-curl");
const issns = fs.readFileSync(filename, "utf-8").split(/\r?\n/);
const csvData = [];
function getPolicies(issns) {
for (const issn of issns) {
const url = "some_api_url" + issn;
const response = request("GET", url);
if (response.statusCode === 200) {
const data = JSON.parse(response.getBody("utf8"));
constructCSV(issn, data);
} else {
console.error("Error fetching data for ISSN: " + issn);
}
}
saveOutput();
}
function constructCSV(issn, data) {
// code to get some data from the json in parameter "data"
// ...
// ...
saveOutput()
}
function saveOutput() {
const csvContent = csvData.join("\n");
fs.writeFileSync(output_file_dir, csvContent);
}
希望这有帮助:)。
您没有向我们展示
text
如何填充数据,但由于您无法控制请求完成的顺序,因此您的代码可能会给出不可预测的结果。
您应该使用 promises 并行执行所有请求,并使用
Promise.all
来检测所有请求何时完成:
const requests = [];
for (let i = 0; i<issns.length; i++) {
url = "some_api_url" + issns[i];
requests.push(new Promise(function(resolve, reject) {
https.get(url, (resp) => {
...
resp.on('end', () => {
data = JSON.parse(data);
resolve(data);
});
}).on("error", (err) => {
console.log("Error: " + err.message);
reject(err);
});
}));
}
Promise.all(requests).then(function(csvData) {
const csvContent = csvData.join("\n");
fs.writeFileSync(output_file_dir, csvContent);
});
csvData
是一个数组,其中各个请求的 data
的顺序与您创建 承诺的顺序相同,无论它们解决的顺序如何。