我正在创建一个简单的节点应用程序。我想达到的目标:
我的应用程序将采取一个网页的链接和一些关键字作为输入。现在我想创建新的网页取决于这些关键字输入。如果我输入优秀的程序员,出色的问题解决者,nodejs开发者。它应该创建3个新文件good_programmer.php,great_problem_solver.php。nodejs_developer.php然后下载这些文件
我建议解决这个问题的方法如下:
const fs = require("fs");
const path = require("path");
const axios = require("axios");
const cheerio = require("cheerio");
const zipadm = require("adm-zip");
const zip = new zipadm();
// initialize app
const app = express();
// to handle the forms
app.use(express.urlencoded({ extended: false }))
// initialize port
const PORT = 8000;
// util functions
function deletePreviousFiles() {
return new Promise((res, rej) => {
fs.readdir(__dirname, (err, files) => {
if (err) throw err;
for (const file of files) {
if (file.includes(".php") || file.includes("sitemap.txt") || file.includes(".zip")) {
fs.unlink(path.join(__dirname, file), err => {
if (err) throw err;
});
}
}
res();
})
})
}
function generateSitemapFile(webpage, words) {
return new Promise((res, rej) => {
let keywords = words.split(",");
for (let i = 0; i < keywords.length; i++) {
let fileName = keywords[i].trim().replace(" ", "_");
let newLink = `${webpage}${fileName}.php`;
fs.appendFile(`sitemap.txt`, `${newLink}n`, function (err) {
if (err) throw err;
});
}
res();
})
}
function generatePHPFiles(data, words) {
return new Promise((res, rej) => {
const $ = data;
$.html();
let keywords = words.split(",");
for (let i = 0; i < keywords.length; i++) {
let fileName = keywords[i].trim().replace(" ", "_");
fs.writeFile(`${fileName}.php`, $.html(), (err) => {
if (err) throw err;
})
}
res();
})
}
function createZipFile() {
return new Promise((res, rej) => {
fs.readdir(__dirname, (err, files) => {
if (err) throw err;
for (const file of files) {
if (file.includes(".php") || file.includes("sitemap.txt")) {
zip.addFile(file);
data = zip.toBuffer();
zip.writeZip("NewPhpFiles.zip");
}
}
res();
})
})
}
// controller
const startApplication = async (req, res, next) => {
try {
const webPageLink = req.body.link;
const seoKeywords = req.body.keywords;
// delete previous files on desk
await deletePreviousFiles();
console.log("Previous Files Deleted...");
// generate sitemap.txt file
await generateSitemapFile(webPageLink, seoKeywords);
console.log("Sitemap Created...");
// get web page response
let response = await axios.get(webPageLink);
const data = await cheerio.load(response.data);
console.log("Data Loaded From Page...")
// create new php files
generatePHPFiles(data, seoKeywords);
console.log("PHP Files Created...")
// create a zip file
createZipFile();
console.log("ZIP Created...")
next();
} catch (error) {
console.log(error)
}
}
const downloadFile = async (req,res) => {
try {
setTimeout(()=>{
res.download("NewPhpFiles.zip");
},1000)
} catch (error) {
console.log(error)
}
}
app.use(startApplication)
// initialize the route for application
app.post("/submit", downloadFile)
// start app
app.listen(PORT, console.log(`App is listening on port: ${PORT}...`));
所以,我正在删除磁盘上现有的php文件,然后创建新文件并压缩它们,但它不下载新文件。创建新文件似乎要花很多时间。
我认为你没有完全理解js是如何工作的。让我们从这个开始。例如,让我们使用deletePreviousFiles函数。fs。Readdir和fs。Unlink有回调,你需要等待那些回调,以确保在函数执行时你想做的一切都完成了。在deletePreviousFiles函数中,您正在等待fs。Readdir,但不用于fs.unlink。也没有正确处理错误。有多种方法可以解决这个问题。当然你可以用回调来做,但是有更简单的解决方案。你可以使用fs包提供的同步函数。或者你可以使用async/await来避免回调混乱。我强烈建议使用fs/promise package。
让我们重构你的函数。
async function deletePreviousFiles() {
let files = await fs.promises.readdir(__dirname);
for (const file of files) {
if (file.includes(".php") || file.includes("sitemap.txt") || file.includes(".zip")) {
await fs.promises.unlink(path.join(__dirname, file))
}
}
}
用这种方法当你调用deletePreviousFiles函数时,你将确保你想做的一切都完成了。(不要忘记这个函数是一个async函数,并且返回一个promise。所以你需要处理这个问题。基本上调用await)
在downloadFile函数中有一个超时函数。我想你这么做是为了等待必要的手术。这是一种错误的做法。对于这种操作,你无法估计需要多长时间。你需要确保它已经完成了。不要使用timeout等待io操作!
同样在startApplication函数中,您使用await调用了一些异步函数,但其他一些函数没有调用。例如,你调用generatePHPFiles没有等待。因此,在传递该行之后,您将在控制台上打印文件创建,但实际上没有。
在其他一切之前,我认为你需要学习回调和async/await在js中的工作原理。如果你还有问题,请提出来。祝你今天过得愉快!