所以我在尝试找出下面的代码片段时遇到了一些问题。截至目前,它正在for循环的'request(scanurl,.....')部分运行之前返回值。循环确实在运行。而且我不认为'lines200'var正在通过更新柜台。我是一个学习者,所以任何解释将不胜感激。
async function processLineByLine(baseData) {
console.log('enter async func')
try {
const fileStream = fs.createReadStream('./file.txt');
let linesTotal = 0;
let lines200 = 0;
const rl = readline.createInterface({
input: fileStream
});
for await (let line of rl) {
console.log('in loop')
const scanurl = (baseData.match(/http/gi)) ? (baseData) : ('https://' + baseData + line);
linesTotal++;
request(scanurl, {json: true}, function (error, response, body) {
let statusCode = response.statusCode;
let htmlBody = body;
//console.log(htmlBody)
//console.log(statusCode)
if (statusCode == "200") {
console.log('in 2nd if')
let $ = cheerio.load(htmlBody);
let titleScrape = $('title').html();
console.log(titleScrape)
if (titleScrape.match(/404 | test/gi)) {
console.log('Matched')
} else {
lines200++;
console.log(lines200)
}
} else {
// Do nothing
}
});
}
return {
total: linesTotal,
count200: lines200,
};
} catch (error) {
console.error(error)
}
}
router.get('/:reqTarget', async (req, res) => {
console.log('starting')
var baseUrl = req.params.reqTarget;
try {
console.log('in the try')
const initTest = await processLineByLine(baseUrl);
const {total, count200} = initTest;
console.log(total, count200)
if (initTest) return res.status(200).send({
message: 'STATUS 200 COUNT: ' + count200 + ' ' + 'TOTAL: ' + total });
} catch (error) {
console.log(error)
}
});
当前输出:
starting
in the try
enter async func
in loop
in loop
in loop
in loop
in loop
in loop
in loop
33 0 //this is the return that is two early
in 2nd if
404 | test
Matched
in 2nd if
404 | test
Matched
答案 0 :(得分:1)
当您有一个包含异步操作的循环时,可以使用以下两个选项之一。您可以并行运行它们,并以某种方式跟踪它们何时完成。或者,您可以一个接一个地依次运行它们。看来您的循环可以用任何一种方式构造,但我将说明顺序选项。
async/await
的出现使我们可以在中间用适当的for
“暂停” await
循环。但是,为此,所有异步操作都必须基于承诺,因此您可以await
进行这些承诺。为此,我已从request()
库切换到request-promise-native
库,该库是使用本地内置Promise的request
库的Promise包装。它还具有另一个不错的功能,它会自动检查2xx状态代码,因此您不必自己执行此操作。
这是该代码的样子:
const rp = require('request-promise-native');
async function processLineByLine(baseData) {
console.log('enter async func')
try {
const fileStream = fs.createReadStream('./file.txt');
let linesTotal = 0;
let lines200 = 0;
const rl = readline.createInterface({
input: fileStream
});
for await (let line of rl) {
console.log('in loop')
const scanurl = (baseData.match(/http/gi)) ? (baseData) : ('https://' + baseData + line);
linesTotal++;
try {
let htmlBody = await rp(scanurl, {json: true});
let $ = cheerio.load(htmlBody);
let titleScrape = $('title').html();
console.log(titleScrape);
if (titleScrape.match(/404 | test/gi)) {
console.log('Matched')
} else {
lines200++;
console.log(lines200)
}
} catch(e) {
console.log(`error on request(${scanurl})`, e);
// like your original code, this will only log the error
// and then continue with the rest of the URLs
}
}
return {
total: linesTotal,
count200: lines200,
};
} catch (error) {
console.error(error)
}
}
router.get('/:reqTarget', async (req, res) => {
console.log('starting')
var baseUrl = req.params.reqTarget;
try {
console.log('in the try')
const initTest = await processLineByLine(baseUrl);
const {total, count200} = initTest;
console.log(total, count200)
res.status(200).send({message: 'STATUS 200 COUNT: ' + count200 + ' ' + 'TOTAL: ' + total});
} catch (error) {
console.log(error)
res.sendStatus(500);
}
});