带有异步意外的无限循环的Node JS

问题描述

我有一个JS文件,它仅在由于超时等原因导致预期错误时才会自动重复自身。

  • 网站无法访问->超时
  • 在“ waitSelector”中查找的标记不存在->达到超时时间

由于无法理解的原因,这会创建内存泄漏错误消息。已经检查了此类问题,以尝试找出它是否已以某种方式链接到Node JS,Puppeteer或Forever库,但尚未遇到其他面临此问题的人。这是我找到的最接近的,但是根据答案here,他的脚本似乎没有错误

JS文件基本上创建了一个具有基本url的服务器,并侦听端口88。当有人输入"http://localhost:88/some_parameters时,似乎代码到达了第一个try-catch,然后返回到console.log(6 )无限期地通过console.log(2)进行操作,直到try catch要么成功要么失败。

我不了解这种行为,因为我希望脚本会一直执行到try catch为止,然后等待响应,然后再根据返回的成功或错误进行修改

在两种情况下,我都输入了两个命令并获得了相同的结果: forever start forever.json node loadPage.js

我花了很多时间尝试解决此问题,但仍然不了解这种行为。我得到了想要的图像,但仍然很奇怪,并最终污染了日志。

任何帮助都将受到欢迎!

更新

仅当try-catch返回错误时,才会发生这种奇怪的行为。返回成功的响应后,代码将正常执行而无需重复任何操作。

loadPage.js

var http = require('http');
var url = require('url');
const puppeteer = require('puppeteer');
const { exit } = require('process');


let baseUrl = "http://localhost:88";
// let url = "chrome://gpu";
// demo/love_down.PHP?clean=0&line1=1,8,0-125&orderid=ORDIB2B-9000105953_1

console.log(1);
http.createServer(function (req,res) {
    console.log(2);
    (async () => {

        console.log(3);
        // headless set to false opens new browser and closes it when process is completed
        const browser = await puppeteer.launch({
            headless: true,args: ['--no-sandBox'],timeout: 10000,devtools: true
        });
        console.log(4);
        const completeUrl = `${baseUrl}${req.url}`;
        console.log(5);
        const parsedUrl = url.parse(completeUrl,true);
        console.log(6);
        const page = await browser.newPage();
        console.log(7);

        // Variable to help determine and log required time for different operations lower in the code.
        let t0 = Date.Now();

        // Console logs used in logs to make them easier to read
        // new Date().toISOString().replace('T',' ').substr(0,19) converts time in acceptable format
        // with space instead of weird characters.
        console.log("[" + new Date().toISOString().replace('T',19) + "] - " +
            "------------------------------Process start for new url------------------------------"
        );
        console.log("[" + new Date().toISOString().replace('T',19) + "] - " +
            "The url being called is: " + `${baseUrl}${parsedUrl.pathname}${parsedUrl.search}`
        );


        // ------------------------------START - GO TO URL PART------------------------------
        // Try-Catch reaching the targeted url
        try {
            await page.goto(`${baseUrl}${parsedUrl.pathname}${parsedUrl.search}`,{
                waitUntil: 'networkidle0',timeout: 10000
            }).then(() => {
                console.log("[" + new Date().toISOString().replace('T',19) + "] - " +
                    "Reached the website!"
                );
            });

        } catch (error) {
            console.log("[" + new Date().toISOString().replace('T',19) + "] - " +
                "the following 'go to url action' error happened: ",error
            );
            console.log("[" + new Date().toISOString().replace('T',19) + "] - " +
                "------------------------------Error 'go to action' end for new url------------------------------"
            );
            browser.close();
            process.exit();
        }

        let t2 = Date.Now();
        console.log("[" + new Date().toISOString().replace('T',19) + "] - " +
            "The 'go to url action' took " + (t2 - t0) + " milliseconds."
        );
        // ------------------------------END - GO TO URL PART------------------------------


        // ------------------------------START - WAIT FOR SELECTOR PART------------------------------
        // try catch to detect the agreed tag's ID selector
        // Once that selected is detected then it means that the model if fully loaded
        try {
            await page.waitForSelector('#uploadsuccess',{
                timeout: 30000
            }).then(() => {
                console.log("[" + new Date().toISOString().replace('T',19) + "] - " +
                    "Got the selector!"
                );
            });
        } catch (error) {
            console.log("[" + new Date().toISOString().replace('T',19) + "] - " +
                "the following 'wait for selector action' error happened: ",19) + "] - " +
                "------------------------------Error 'wait for selector action' end for new url------------------------------"
            );
            browser.close();
            process.exit();
        }

        let t3 = Date.Now();
        console.log("[" + new Date().toISOString().replace('T',19) + "] - " +
            "The 'waitForSelector' action took " + (t3 - t2) + " milliseconds."
        );
        // ------------------------------END - WAIT FOR SELECTOR PART------------------------------


        // ------------------------------START - IMAGE SAVING PART------------------------------
        // Take a printscreen and saving the image in the corresponding folder
        try {
            await page.screenshot({
                path: "./images/" + new Date().toISOString().replace('T',19) + "-apm-3d.png"
            }).then(() => {
                console.log("[" + new Date().toISOString().replace('T',19) + "] - " +
                    "Image saved"
                );
            });

        } catch (error) {
            console.log("[" + new Date().toISOString().replace('T',19) + "] - " +
                "the following 'image saving' error happened: ",19) + "] - " +
                "------------------------------Error 'image saving' end for new url------------------------------"
            );
            browser.close();
            process.exit();
        }
        // ------------------------------END - IMAGE SAVING PART------------------------------


        let t1 = Date.Now();
        console.log("[" + new Date().toISOString().replace('T',19) + "] - " +
            "The whole process took " + (t1 - t0) + " milliseconds."
        );
        console.log("[" + new Date().toISOString().replace('T',19) + "] - " +
            "------------------------------Process end for new url------------------------------"
        );
        browser.close();

    })()

}).listen(88)

forever.log

1
2
3
4
5
6
7
[2020-09-09 10:52:14] - ------------------------------Process start for new url------------------------------
[2020-09-09 10:52:14] - The url being called is: http://localhost:88/demo/love_down.PHP?clean=0&line1=1,0-125&orderid=ORDIB2B-9000105953_1
2
3
4
5
6
7
[2020-09-09 10:52:14] - ------------------------------Process start for new url------------------------------
[2020-09-09 10:52:14] - The url being called is: http://localhost:88/demo/love_down.PHP?clean=0&line1=1,0-125&orderid=ORDIB2B-9000105953_1
2
3
4
5
6
7
[2020-09-09 10:52:15] - ------------------------------Process start for new url------------------------------
[2020-09-09 10:52:15] - The url being called is: http://localhost:88/demo/love_down.PHP?clean=0&line1=1,0-125&orderid=ORDIB2B-9000105953_1
2
3
4
5
6
7
[2020-09-09 10:52:16] - ------------------------------Process start for new url------------------------------
[2020-09-09 10:52:16] - The url being called is: http://localhost:88/demo/love_down.PHP?clean=0&line1=1,0-125&orderid=ORDIB2B-9000105953_1
2
3
4
5
6
7
[2020-09-09 10:52:17] - ------------------------------Process start for new url------------------------------
[2020-09-09 10:52:17] - The url being called is: http://localhost:88/demo/love_down.PHP?clean=0&line1=1,0-125&orderid=ORDIB2B-9000105953_1
2
3
(node:12919) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 exit listeners added to [process]. Use emitter.setMaxListeners() to increase limit
(node:12919) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 SIGINT listeners added to [process]. Use emitter.setMaxListeners() to increase limit
(node:12919) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 SIGTERM listeners added to [process]. Use emitter.setMaxListeners() to increase limit
(node:12919) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 SIGHUP listeners added to [process]. Use emitter.setMaxListeners() to increase limit
4
5
6
7
[2020-09-09 10:52:17] - ------------------------------Process start for new url------------------------------
[2020-09-09 10:52:17] - The url being called is: http://localhost:88/demo/love_down.PHP?clean=0&line1=1,0-125&orderid=ORDIB2B-9000105953_1
2
3
4
5
6
7
[2020-09-09 10:52:18] - ------------------------------Process start for new url------------------------------
[2020-09-09 10:52:18] - The url being called is: http://localhost:88/demo/love_down.PHP?clean=0&line1=1,0-125&orderid=ORDIB2B-9000105953_1
2
3
4
5
6
7
[2020-09-09 10:52:19] - ------------------------------Process start for new url------------------------------
[2020-09-09 10:52:19] - The url being called is: http://localhost:88/demo/love_down.PHP?clean=0&line1=1,0-125&orderid=ORDIB2B-9000105953_1
2
3
4
5
6
7
[2020-09-09 10:52:20] - ------------------------------Process start for new url------------------------------
[2020-09-09 10:52:20] - The url being called is: http://localhost:88/demo/love_down.PHP?clean=0&line1=1,0-125&orderid=ORDIB2B-9000105953_1
2
3
4
5
6
7
[2020-09-09 10:52:21] - ------------------------------Process start for new url------------------------------
[2020-09-09 10:52:21] - The url being called is: http://localhost:88/demo/love_down.PHP?clean=0&line1=1,0-125&orderid=ORDIB2B-9000105953_1
2
3
4
5
6
7
[2020-09-09 10:52:22] - ------------------------------Process start for new url------------------------------
[2020-09-09 10:52:22] - The url being called is: http://localhost:88/demo/love_down.PHP?clean=0&line1=1,0-125&orderid=ORDIB2B-9000105953_1
2
3
4
5
6
7
[2020-09-09 10:52:23] - ------------------------------Process start for new url------------------------------
[2020-09-09 10:52:23] - The url being called is: http://localhost:88/demo/love_down.PHP?clean=0&line1=1,0-125&orderid=ORDIB2B-9000105953_1
2
3
4
5
6
7
[2020-09-09 10:52:24] - ------------------------------Process start for new url------------------------------
[2020-09-09 10:52:24] - The url being called is: http://localhost:88/demo/love_down.PHP?clean=0&line1=1,0-125&orderid=ORDIB2B-9000105953_1
2
3
[2020-09-09 10:52:24] - the following 'go to url action' error happened:  TimeoutError: Navigation timeout of 10000 ms exceeded
    at /Users/sebastienponcelet/Documents/3d-puppeteer/3d-puppeteer/node_modules/puppeteer/lib/cjs/puppeteer/common/LifecycleWatcher.js:106:111
    at async FrameManager.navigateFrame (/Users/sebastienponcelet/Documents/3d-puppeteer/3d-puppeteer/node_modules/puppeteer/lib/cjs/puppeteer/common/FrameManager.js:88:21)
    at async Frame.goto (/Users/sebastienponcelet/Documents/3d-puppeteer/3d-puppeteer/node_modules/puppeteer/lib/cjs/puppeteer/common/FrameManager.js:405:16)
    at async Page.goto (/Users/sebastienponcelet/Documents/3d-puppeteer/3d-puppeteer/node_modules/puppeteer/lib/cjs/puppeteer/common/Page.js:826:16)
    at async /Users/sebastienponcelet/Documents/3d-puppeteer/3d-puppeteer/loadPage.js:49:13
[2020-09-09 10:52:24] - ------------------------------Error 'go to action' end for new url------------------------------
error: Forever detected script exited with code: 0
error: Script restart attempt #1
1
error: restarting script because /Users/sebastienponcelet/Documents/3d-puppeteer/3d-puppeteer/stack-overflow.md changed
error: Forever detected script was killed by signal: SIGKILL
error: Script restart attempt #2
1

解决方法

问题是您一次又一次地调用同一HTTP服务器,而没有返回响应。

HTTP服务器正在侦听端口88:

http.createServer(function (req,res) {
  ...
}).listen(88)

然后您发出第一个HTTP请求,以便该过程开始。 2-7点之后,过程到达以下行:

await page.goto(`${baseUrl}${parsedUrl.pathname}${parsedUrl.search}`,{

这指示操纵p​​到页面http://localhost:88/demo/love_down.php?clean=0&line1=1,8,0-125&orderid=ORDIB2B-9000105953_1(也位于localhost:88上),再次击中同一HTTP服务器。

第二个请求到达时,它会执行相同的过程,启动浏览器,提取URL,然后向http://localhost:88/...发出请求,从而生成另一个浏览器,并发出另一个请求,依此类推。这就是为什么您会一遍又一遍地看到2-7的原因,这是一个无限递归的教科书示例。

由于所有浏览器都在等待响应,但是这种响应永远不会发生,因此它们最终会超时,这就是为什么您看到错误的原因。

,

您的catch块中包含process.exit(),这将关闭服务器。永远无法看到该进程被杀死并重新启动它。只需删除该行即可。

,

我已经成功地解决了这个问题,只需在执行操作时删除try-catch即可。真的不知道为什么,但是这使程序无限期地循环直到返回响应。

那里的代码现在看起来像这样:

// ------------------------------START - GO TO URL PART------------------------------
    await page.goto(`${baseUrl}${parsedUrl.pathname}${parsedUrl.search}`,{
        waitUntil: 'networkidle2',timeout: 10000
    })

    let t2 = Date.now();
    console.log("[" + new Date().toISOString().replace('T',' ').substr(0,19) + "] - " +
        "The 'go to url action' took " + (t2 - t0) + " milliseconds."
    );
    // ------------------------------END - GO TO URL PART------------------------------

很高兴有任何评论来解释为什么这样做可以解决问题。