错误:调用和重试上次分配失败-Javascript堆内存不足
我正在学习NodeJS和Javascript。我正试图开发一个应用程序来阅读和下载漫画 首先我想建立一个数据库。这就是我遇到的问题。 当我在内存为4GB的服务器上运行我的程序时(用以填充我的数据库),我得到了内存不足的致命错误Javascript堆 当我用8GB内存在本地计算机上运行相同的程序时,一切都正常工作 这是我用漫画章节填充数据库的代码错误:调用和重试上次分配失败-Javascript堆内存不足,javascript,memory,memory-management,memory-leaks,Javascript,Memory,Memory Management,Memory Leaks,我正在学习NodeJS和Javascript。我正试图开发一个应用程序来阅读和下载漫画 首先我想建立一个数据库。这就是我遇到的问题。 当我在内存为4GB的服务器上运行我的程序时(用以填充我的数据库),我得到了内存不足的致命错误Javascript堆 当我用8GB内存在本地计算机上运行相同的程序时,一切都正常工作 这是我用漫画章节填充数据库的代码 function insertChapters(callback){ sql_selectAll("Mangas", function (se
function insertChapters(callback){
sql_selectAll("Mangas", function (selectError, selectResult) {
if(!selectError){
selectResult.forEach(function (mangaItem, mangaIndex) {
gin.mangafox.chapters(mangaItem.Title)
.then(chapters =>{
chapters.forEach(function (chapterItem) {
var Chapter = {
Title: chapterItem.name,
NR: chapterItem.chap_number,
URL: chapterItem.src,
MangaID: mangaItem.MangaID,
MangaName: mangaItem.Title,
VolumeNR: chapterItem.volume
};
sql_insertInto("Chapters", Chapter, function (insertError, insertResult) {
if(!insertError){
var insertedChapter =
"------------------------------------------------------------------------\n" +
" Added new Chapter: " + Chapter.NR + " For: " + mangaItem.Title + "\n" +
"------------------------------------------------------------------------\n";
callback(null,insertedChapter ,insertResult);
}
else{
if(insertError.code === "ER_DUP_ENTRY") {
var dupEntry = "------------------------------------------------------------------------\n" +
" Duplicate Entry: Chapter: " + Chapter.NR + " For: " + mangaItem.Title + "\n" +
"------------------------------------------------------------------------\n"
callback(null, dupEntry, null);
}
else{
callback(insertError, null, null);
}
}
})
})
})
.catch(fetchChapterError => {
callback(fetchChapterError, null, null);
})
})
}
else{
callback(selectError, null, null);
}
});
}`
我真的不知道如何解决这个问题,因为我不确定问题是什么:
您正在同时为每个SQL结果调用mangafox端点,而不是一次调用一个端点或分块调用一个端点。你可以试着用这个。我不熟悉您正在使用的sql API,但假设方法
sql\u selectAll
和sql\u insertInto
在没有回调的情况下返回,您可以将函数重写为如下内容:
async function insertChapters(callback) {
try {
const mangas = await sql_selectAll("Mangas");
for (const mangaItem of mangas) {
const chapters = await gin.mangafox.chapters(mangaItem.Title);
for (const chapterItem of chapters) {
const Chapter = {
Title: chapterItem.name,
NR: chapterItem.chap_number,
URL: chapterItem.src,
MangaID: mangaItem.MangaID,
MangaName: mangaItem.Title,
VolumeNR: chapterItem.volume
};
try {
const insertResult = await sql_insertInto("Chapters", Chapter);
const insertedChapter =
"------------------------------------------------------------------------\n" +
" Added new Chapter: " + Chapter.NR + " For: " + mangaItem.Title + "\n" +
"------------------------------------------------------------------------\n";
callback(null, insertedChapter, insertResult);
} catch (error) {
if (error.code === "ER_DUP_ENTRY") {
const dupEntry = "------------------------------------------------------------------------\n" +
" Duplicate Entry: Chapter: " + Chapter.NR + " For: " + mangaItem.Title + "\n" +
"------------------------------------------------------------------------\n";
callback(null, dupEntry, null);
} else {
throw error;
}
}
}
}
} catch (error) {
callback(error, null, null);
}
}
请注意await
关键字-这些关键字在async function
s中是允许的,本质上是告诉JS引擎暂停异步函数的执行并执行其他操作,直到等待的承诺得到解决
还请注意,在使用wait
关键字处理承诺时,可以使用常规的老式try
/catch
块!我没有做任何特殊的操作来处理fetchchapterror
,因为它将由最外层的catch
块处理!另外,对于插入错误,如果它不是重复的条目,我们可以重新显示该错误,并让最外层的catch块也捕获该错误
如果SQL函数不返回承诺,那么在节点版本8(最新版本)上,可以使用util.promisify
:
const util = require('util');
sql_selectAll = util.promisify(sql_selectAll);
如果您没有使用Node 8,那么您可以使用另一个
promisify
实现(例如,签出),或者您可以非常轻松地编写自己的实现(阅读关于promises的MDN文章)。初始SQL查询返回了多少个结果?另外,需要注意的是,您正在为SQL中的每个结果立即调用gin.mangafox.chapters
端点,然后等待所有结果返回。这就是JS中异步编程的工作原理——代码在异步调用等待时保持运行。当您调用forEach
时,它将立即为每个项运行给定的函数,而不等待在调用之间返回任何异步结果。如果数据库中有数百个漫画,则同时执行数百个API调用。初始查询返回大约19000个结果,这些19000个结果中的每一个平均有15-20个章节。有没有更好的更方便记忆的方法?我仍在努力学习异步编程。感谢您的快速回复!是的,因此您同时对mangafox API端点执行19000个请求。内存不足是因为程序试图跟踪太多的异步请求,而不是一次一个或分块执行。你有没有研究过JS的异步/等待特性?另外,您在SQL调用中使用了什么?我不认识像sql\u selectAll
和sql\u insertInto
这样的方法。如果这些方法返回承诺,我可以向您展示如何使用async/await构造函数。他们目前不兑现承诺。但我可以改变它。但是我该怎么做呢?我不熟悉async/Wait,但我对一切都很开放。你能告诉我你的想法吗?:)非常感谢你的帮助!!!看看我的答案,我想这会有点帮助。它一次调用一个端点,而不是成批调用,因此可能需要很长时间才能运行。一旦您理解了一次一个的代码,我将让您自己决定如何进行批处理。(提示:请阅读关于Thanke you的MDN文章。我会尝试一下。您非常有帮助!@calgara12不客气。另外请注意,async function
s会自动返回,因此最好去掉函数的回调参数,使用insertChapters()。然后(successCallback)。catch(errorCallback)
。或者,您可以使用另一个异步函数调用尝试{wait insertChapters()}catch(error){/*…*/}
。但是,在代码的顶层,您可能需要使用然后
/捕获
一次,因为您只能在异步函数中使用等待
,并且希望能够处理该异步函数返回的承诺。
const util = require('util');
sql_selectAll = util.promisify(sql_selectAll);