javascript - 在 JS /Node JS 中使用 promise 每次都会遍历每个对象
问题描述
我正在尝试制作一个程序来验证链接是否损坏或工作。我是 JS 的新手,也是 Promise 的新手。我正在测试一个包含一个损坏的链接和一个工作的降价文件,显然,每次我运行代码时,它都会运行两次(每个链接一个,如果我添加 3 个链接,它会运行 3 次)。
这是我收到的输出
这是我的代码
const path = require('path');
const fs = require('fs');
const fetch = require('node-fetch');
const inputPath = process.argv[2];
const inputOptions = process.argv[3];
const inputOptionsTwo = process.argv[4];
let okLinks = [];
let okLinksCount = 0;
let notOkLinks = [];
let notOkLinksCount = 0;
const checkFilePath = () => {
let pathExt = path.extname(inputPath);
if (pathExt == '.md') {
console.log('md file')
parseFile(inputPath);
} else {
console.log('file not recognized');
}
};
const parseFile = (inputPath) => {
fs.readFile(inputPath, 'utf8', (err, data) => {
if (!err) {
const regex = new RegExp(/(https?:\/\/[^\s\){0}]+)/g);
const links = data.match(regex);
if (links) {
//function to validate, pass the links as parameter
validateLinks(links);
} else {
console.log('no links found');
}
} else {
//error reading files
console.log('an error ocurred');
console.error(error.message);
}
});
};
const validateLinks = (links) => {
for (let i = 0; i < links.length; i++) {
const p = new Promise(resolve => {
fetch(links[i])
.then(res => {
if (res.status >= 400) {
notOkLinksCount++;
notOkLinks.push(links[i] + ' FAIL : ' + res.status);
} else {
okLinks.push(links[i] + ' OK : ' + res.status);
okLinksCount++;
}
console.log('f');
if (inputOptions === '--validate') {
setTimeout(function() {
console.log(notOkLinks);
console.log(okLinks);
}, 500);
} else if (inputOptions === '--stats' && inputOptionsTwo === '--validate') {
setTimeout(function() {
console.log('Total: ' + links.length + '\n' + 'Ok: ' + okLinksCount);
console.log('Broken: ' + notOkLinksCount);
console.log(notOkLinks);
console.log(okLinks);
}, 2800);
} else if (inputOptions === '--stats') {
setTimeout(function() {
console.log('Total: ' + links.length + '\n' + 'Ok: ' + okLinksCount);
}, 2800);
}
}).catch((error) => {
console.error('Error');
});
})
}
}
checkFilePath();
解决方案
如果您能够在您的环境中使用async/await语法,那么它将使 Promise 的推理更容易。
目前代码不等待异步代码完成,这就是我认为setTimeouts
添加的原因。像这样使用它们是不稳定的,因为它们是在猜测代码需要多长时间才能完成,而不是真正等到它完成或出错。
尽量避免将回调混入 Promise 代码fs.readFile
中,比如 Nodefs
现在提供了一个 Promise API。
Bluebird Promise 库提供了一些帮助器和Promise.map
或Promise.filter
用于处理数组。另外Promise.delay
,如果您确实需要setTimeout
出于其他原因使用。
结合所有这些意味着对代码进行相当多的重组。
const fsp = require('fs').promises;
const fetch = require('node-fetch');
const Promise = require('bluebird');
const parseFile = async (inputPath) => {
try {
const data = await fsp.readFile(inputPath, 'utf8')
const regex = new RegExp(/(https?:\/\/[^\s\){0}]+)/g);
const links = data.match(regex);
if (!links) {
return console.log('no links found');
}
//function to validate, pass the links as parameter
return validateLinks(links);
} catch (error) {
//error reading files
console.error('An error occurred processing '+inputPath);
throw error
}
};
const checkLink = async (link) => {
try {
const res = await fetch(link)
if (res.status >= 400) {
const error = new Error(`'Request failed for ${link} with ${res.status}`)
error.res = res
error.status = status
throw error
}
return link;
}
catch (error) {
error.link = link
throw error
}
}
const validateLinks = async (links) => {
const notOkLinks = [];
const okLinks = await Promise.filter(links, async link => {
try {
return checkLink(link)
}
catch (error) {
console.error('Error for %s', link, error);
notOkLinks.push(error)
return false
}
})
return {
okLinks,
notOkLinks,
}
}
然后您可以重新实现checkFilePath
toawait parseFile()
并处理对象中返回的okLinks
and的日志记录。notOkLinks
删除所有setTimeout
s ,因为await
will 在继续之前等待承诺完成。
推荐阅读
- java - 无法在 main.java (JavaFX) 中添加 Canvas
- java - 带有@JsonProperty 的通用 JSON 响应
- stormcrawler - Stormcrawler 中的 URL 重定向使该页面的爬网处于错误状态
- json - Vanilla JS (FUN ONE):从字符串“map”访问深埋 JSON 节点的最佳方式
- python - 使用 Python3 itertools 排列:如何指定所有 r > 1
- javascript - jQuery - 在页面之间来回更改时保留表单数据
- javascript - 快递服务器工作,但没有将任何内容记录到 vs 代码终端
- haskell - 输出元组列表的 Haskell 函数中的非详尽模式
- reactjs - ASP NET Core 3.1 如何发布 FormData
- powerbi - Direct Query 中的 DAX 筛选器