Javascript MaxListenerSexCeed矮化:可能的事件发射器内存泄漏检测
我已经阅读了有关此错误的信息,知道它是什么,也知道如何通过将Javascript MaxListenerSexCeed矮化:可能的事件发射器内存泄漏检测,javascript,node.js,puppeteer,Javascript,Node.js,Puppeteer,我已经阅读了有关此错误的信息,知道它是什么,也知道如何通过将MaxListeners设置为0来禁用它。但是我想知道是什么导致了这个错误,这样我才能正确地处理它 基本上,这里有一个机器人来检查我的帐户是否有新消息。我需要一次检查很多帐户,所以我写了这个机器人来做这件事。我在这段代码中有4个函数: 1 - load_proxy -> reads list of proxies from a file and puts them into an array 2 - load_accounts -
MaxListeners
设置为0
来禁用它。但是我想知道是什么导致了这个错误,这样我才能正确地处理它
基本上,这里有一个机器人来检查我的帐户是否有新消息。我需要一次检查很多帐户,所以我写了这个机器人来做这件事。我在这段代码中有4个函数:
1 - load_proxy -> reads list of proxies from a file and puts them into an array
2 - load_accounts -> reads list of accounts from a file and puts them into an array
3 - init-> opens a browser , in a while loop fetching accounts and calling the next function
4 - open_tab-> opens a tab in the browser and checks the account and calles the next function to log the result
5 - wite_to_file-> writing the result into a text file
const puppeteer = require('puppeteer');
const fs = require('fs');
const PROXYSTACK = [] ;
const PROXYDB = [] ;
const ACCOUNTSTACK = [] ;
const ACCOUNTDB = [] ;
var inprogress = false ;
setInterval(()=>load_proxy() , 5000 );
setInterval(()=>load_accounts() , 5000 );
setInterval(function(){
if( !inprogress)
{
init();
}
} , 2000 );
function load_proxy(){
var lines = fs.readFileSync('./proxy.txt', 'utf-8')
.split('\n');
for(var i = 0 ; i< lines.length ; i++ )
{
let line = lines[i];
if(line == '' || typeof line == 'undefined')
{
continue ;
}
line = line.replace('\r' , '');
if(PROXYDB.includes(line))
continue ;
PROXYSTACK.push(line);
PROXYDB.push(line);
}
}
function load_accounts(){
var lines = fs.readFileSync('./accounts.txt', 'utf-8')
.split('\n');
for(var i = 0 ; i< lines.length ; i++ )
{
let line = lines[i];
if(line == '' || typeof line == 'undefined')
{
continue ;
}
line = line.replace('\r' , '');
if(ACCOUNTDB.includes(line))
continue ;
ACCOUNTDB.push(line);
ACCOUNTSTACK.push(line);
}
}
async function init(){
inprogress = true ;
if(PROXYSTACK.length <= 0 )
{
console.log('========================================= > OUT OF PROXY !!!!');
inprogress = false ;
return ;
}
if(ACCOUNTSTACK.length <= 0 )
{
console.log('========================================= > OUT OF ACCOUNT !!!!');
inprogress = false ;
return ;
}
var ipport = PROXYSTACK.pop().replace('\r' , '');
console.log(` ----> current ${ipport} `);
var browser = await puppeteer.launch({headless: true , args: ['--proxy-server=' + ipport , '--no-sandbox', '--disable-setuid-sandbox' , ]});
browser._process.once('close', () => {
console.log(' ------------------------ closed !');
inprogress = false;
});
browser.on('disconnected', () => {
console.log(' ------------------------ disconnecte !');
inprogress = false;
});
var mainpage = await browser.newPage();
await mainpage.setViewport({width: 1200, height: 1000});
while( inprogress )
{
var line_number = ACCOUNTSTACK.length ;
if(line_number == 0 )
{
inprogress = false ;
break ;
}
var account = ACCOUNTSTACK.pop();
console.log(account);
var check = await open_tab(account , line_number , mainpage);
if(check === 'fatalerror')
{
console.log('========================================= > FATAL ERROR CHANGING IP ');
try {
await browser.close();
}
catch (e) {
}
inprogress = false ;
}
}
}
async function open_tab(account , line_num , mainpage ) {
console.log(` ---- > checking ${account} `);
let link = `https://example.com`;
try {
let user_password = account.split(':');
if(!await mainpage.$('#username'))
{
console.log('...loading login page');
await mainpage.goto(link , {timeout: 0});
console.log('...done');
if(await mainpage.$('.fatalerror'))
{
ACCOUNTSTACK.push(account);
await mainpage.screenshot({path: './fatalerror-a-'+line_num+'.jpg' });
return 'fatalerror';
}
console.log('...waitnign for login filds');
await Promise.race([
mainpage.waitForSelector('#username'),
mainpage.waitForSelector('.fatalerror'),
]).catch(function (error) {
throw new Error(error);
});
if(await mainpage.$('.fatalerror'))
{
ACCOUNTSTACK.push(account);
await mainpage.screenshot({path: './fatalerror-b-'+line_num+'.jpg' });
return 'fatalerror';
}
console.log('...done');
}
console.log('...typing user password');
await mainpage.$eval('#username', (el ) => el.value = '' );
await mainpage.$eval('#password', (el ) => el.value = '' );
await mainpage.type('#username', user_password[0], {delay: 10})
await mainpage.type('#password', user_password[1], {delay: 10})
console.log('...done');
console.log('...clicking login button');
await mainpage.click('button.primary-button')
await Promise.race([
mainpage.waitForSelector('.theme-noticeerror-font'), // timeout
mainpage.waitForSelector('.empty-inbox'),
mainpage.waitForSelector('.new-message'),
mainpage.waitForNavigation(),
]).catch(function (error) {
throw new Error(error);
});
console.log('...done');
if (await mainpage.$('.theme-noticeerror-font'))
{
console.log(account + '-- '+ line_num +' --> TIMEOUT')
ACCOUNTSTACK.push(account);
await mainpage.screenshot({path: './timeout'+line_num+'.jpg' });
return 'fatalerror';
}
else if (await mainpage.$('.empty-inbox'))
{
console.log(account + '-- '+ line_num +' --> empty');
wite_to_file('empty.txt' , account );
}
else if (await mainpage.$('.new-message'))
{
console.log(account + '-- '+ line_num +' --> new message')
wite_to_file('newmsg.txt' , account );
}
}
catch(e)
{
console.log(`--------ERRRO----${account}-${line_num}---------------------`);
await mainpage.screenshot({path: './images/error'+line_num+'.jpg' });
ACCOUNTSTACK.push(account);
const html = await mainpage.content();
fs.writeFileSync('./images/error'+line_num+'.html', html);
}
}
function wite_to_file( file , acc){
fs.appendFile('./' + file , `${acc}\n` , function (err) {})
}
我不确定是什么原因造成的,或者是否严重
使用--跟踪警告运行代码后
(node:992) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 framedetached listeners added to [FrameManager]. Use emitter.setMaxListeners() to increase limit
at _addListener (events.js:261:17)
at FrameManager.addListener (events.js:277:10)
at Function.addEventListener (/home/robot/node_modules/puppeteer/lib/helper.js:188:13)
at new NavigatorWatcher (/home/robot/node_modules/puppeteer/lib/NavigatorWatcher.js:50:14)
at Page.waitForNavigation (/home/robot/node_modules/puppeteer/lib/Page.js:618:21)
at open_tab (/home/robot/psn.js:212:22)
at processTicksAndRejections (internal/process/task_queues.js:85:5)
at async init (/home/robot/psn.js:115:21)
(node:992) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 response listeners added to [NetworkManager]. Use emitter.setMaxListeners() to increase limit
at _addListener (events.js:261:17)
at NetworkManager.addListener (events.js:277:10)
at Function.addEventListener (/home/robot/node_modules/puppeteer/lib/helper.js:188:13)
at Page.waitForNavigation (/home/robot/node_modules/puppeteer/lib/Page.js:621:29)
at open_tab (/home/robot/psn.js:212:22)
at processTicksAndRejections (internal/process/task_queues.js:85:5)
at async init (/home/robot/psn.js:115:21)
这通常发生在调用过多ansync函数而未完成时。假设所有异步函数都有一个最小超时(0ms),它们总是被推到堆栈的末尾,并且在循环调用它们之前,它们中的任何一个都不会完成
无论如何,如果你想让大量的异步事件并行发生
通过将MaxListeners设置为0来禁用它
或者,您可以使用for循环(而不是forEach),将其包装在带有waitis的异步函数中,以使代码完全同步。如果运行时不是对象,这可以使日志记录变得更好
// example of de-parallelizing
(async () => {
const userIds = await myDb.getAllUserIds();
const usersWithoutFirstnames = [];
for (userId of userIds) {
console.log("Getting first name of user:", userId);
const firstName = await myDb.getFirstName(userId);
if (firstName) {
console.log("SUCCESS: ", firstName);
} else {
console.log("First name not found");
usersWithoutFirstnames.push(userId);
}
}
})(); // closures are back
我认为问题与这些部分有关:
setInterval(函数(){
如果(!inprogress)
{
init();
}
}, 2000);
异步函数init(){
...
浏览器。\处理.once('close',()=>{
console.log('---------------------------closed!');
inprogress=假;
});
browser.on('断开连接',()=>{
log('---------------------------disconnect!');
inprogress=假;
});
...
}
每2秒触发两个事件侦听器(如果进程中的inprogress
等于false
),但仅在进程遇到fatalerror
时关闭这些侦听器
if(检查=='fatalerror'){
等待浏览器关闭();
}
因此,在您的代码逻辑中,我认为大多数close
和disconnected
侦听器仍在侦听/等待事件发生,就像您收到的警告一样,您可能同时有11个以上的侦听器。您应该始终关闭browser
实例(除非您想重用浏览器实例,因为每个浏览器实例都有不同的ipport
,所以它似乎不适合您的情况),我认为这两个事件侦听器都可以被使用,并适当地释放内存
所以,也许您希望始终像这样关闭浏览器:
异步函数init(){
...
while(进行中){
...
}
等待浏览器关闭();
}
我在运行包含异步函数的循环时遇到过这种情况。就像从数据库中提取用户一样。我倾向于确保我现在在
中等待(…of…)
循环中的所有内容,这样就不会有并行事件调用(而且我的脚本日志记录更容易阅读)。@max,您在一段时间后或开始运行程序后立即收到错误消息?@max,你能像节点--trace warnings app.js那样运行你的应用程序吗?看看跟踪告诉你什么?@max,这方面有什么更新吗?@TarunLalwani抱歉耽搁了。。。我在问题的底部添加了请求的数据,我在while循环中调用异步函数,可能就是。。。。但我在给他们打电话时用wait。。。所以他们不可能是平行的。。。对吧?while(inprogress){var check=wait open_tab(account,line_number,mainpage);}
Yeah,这真的应该在继续之前完成。除非有一个未等待的包装循环(任何forEach),或者如果由于某种原因打开的选项卡在等待后未完成。也许它有一些异步簿记功能,不值得阻止线程?有第五个功能,我现在添加到代码中,我认为这与问题无关,但现在我认为这可能是it@max,您是否尝试过此方法,并有任何反馈?任何进一步的信息都可能有助于解决这一问题。对于asnwer,thanx,抱歉,耽搁了。。。。只有当inprogress==false
并且因为在init
函数的第一行中,我设置了inprogress=true
时,interval
才调用init
函数。。。它不可能每2秒触发一次listners,对吗?@max,是的,但即使在inprogress=true
时不触发新的init
任务,进程也不会关闭每个init
任务的浏览器实例,除非它遇到fatalerror
,所以旧的侦听器仍然存在
process.setMaxListeners(0);
// example of de-parallelizing
(async () => {
const userIds = await myDb.getAllUserIds();
const usersWithoutFirstnames = [];
for (userId of userIds) {
console.log("Getting first name of user:", userId);
const firstName = await myDb.getFirstName(userId);
if (firstName) {
console.log("SUCCESS: ", firstName);
} else {
console.log("First name not found");
usersWithoutFirstnames.push(userId);
}
}
})(); // closures are back