【问题标题】:NodeJS async function doesn't run when inside of a while true loopNodeJS异步函数在while true循环内不运行
【发布时间】:2020-12-01 06:19:29
【问题描述】:

我试图通过使用 puppeteer 捕获 cookie 并将 cookie 添加到本地 json 文件来创建 cookie 生成器。一切正常,除非我试图让函数每 5 秒运行一次,但它会挂起并且永远不会完成该函数。在python中我曾经做过

while True:
   main()
   time.sleep(5)

但在节点中我正在这样做,它挂起。没有错误,它只是挂起。

while (true){
   main()
}

我的函数永远不会运行,它只是挂起。下面是 main 函数的简化。

function sleep(ms) {
    return new Promise((resolve) => {
      setTimeout(resolve, ms);
    });
}

main = async () => {
    let start = now();

    puppeteer.launch( {headless:true} ).then( async (browser) => {
        console.log('Loaded Browser Successfully!')
        const page = await browser.newPage()
        await page.goto('some link')
        const cookies = await page.cookies();

        await sleep(5000)
        for(let cookie of cookies){
            if (cookie.name == 'some cookie')
                console.log(cookie)
        }
        await browser.close()
        return cookies
    }).then( async (cookies) => {
        let rawData = fs.readFileSync(path.join(__dirname,'Cookies.json'))
        let cookieJar = JSON.parse(rawData)
        cookieJar.push(cookies)
        console.log(cookieJar.length)
        await fs.writeFileSync(path.join(__dirname,'Cookies.json'), JSON.stringify(cookieJar))

        let end = now();
        console.log(`It took ${end - start}ms`)
        return
    })
    
}

我在这里做错了什么?

【问题讨论】:

  • 没有什么 main 对 while 循环是否继续有任何交互作用。因此,无论 main 是否完成了它需要做的事情,while 循环都会继续,直到它被硬停止。
  • 温馨提示:您的代码表明您还没有完全理解 JS 中的异步基础知识。另外,您通常不会混合使用awaitthen(...)(通常,您应该尽可能始终使用await)。 MDN 是学习 JS'concurrency modelPromiseawait 基础知识的好地方。

标签: node.js asynchronous while-loop async-await


【解决方案1】:

JS 从不并行运行代码,只能异步运行。您的异步Promise-callback 只能在您当前的执行完成后运行。由于您使用了while (true),它永远不会完成。

对于您的问题,setInterval 是理想的:

setInterval(main, 5000)

【讨论】:

  • 这行得通,但现在我的await fs.writeFileSync(path.join(__dirname,'Cookies.json'), JSON.stringify(cookieJar)) 不起作用,它在不等待我的文件更新时重新启动功能,我该如何解决这个问题?
  • 由于您使用的是writeFileSyncsync 版本),因此您首先不需要await。但一般来说,如果您只想在 完成后 5 秒而不是 每 5 秒重新触发操作,那么调用 setTimeout(main, 5000) 会更好在程序的最后(即在您的console.log 附近),而不是使用setInterval
  • await fs.writeFileSync(path.join(__dirname,'Cookies.json'), JSON.stringify(cookieJar)) let end = now(); console.log(`It took ${end - start}ms`) }) setTimeout(main, 10000) } setTimeout(main, 10000) 这很完美,谢谢
  • 好的,但也请注意我对这个问题的评论。我现在在您的评论中看到两个setTimeout(main, 10000)s。如果做错了,这可能会导致两个独立的计时器定期重新触发动作(因此每 10 秒触发两次动作),或者 - 更糟糕的是 - 计时器的定期重复导致 setTimeout- 的数量不断增加调用会堆积您的事件队列并在某种程度上使您的应用程序瘫痪。
猜你喜欢
  • 2016-01-28
  • 2018-07-26
  • 2019-01-17
  • 1970-01-01
  • 2023-04-06
  • 1970-01-01
  • 2020-10-08
  • 1970-01-01
  • 2019-07-04
相关资源
最近更新 更多