【问题标题】:How to use async function with set interval如何使用设置间隔的异步函数
【发布时间】:2021-01-01 15:47:43
【问题描述】:
async function getContent(){
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto(url);
    const content =  await page.content();
    await console.log(content);
    await browser.close();
}

setInterval(searchTarget(), 13000);

我有这个异步函数,它使用 puppeteer 从网页获取内容。我希望能够经常检查网页,所以我尝试使用 setinterval 但我一直收到错误。有什么想法吗?

【问题讨论】:

  • “我不断收到错误” - 什么错误
  • 我的建议:不要使用 setInterval。在解析中再次调用该函数并超时
  • 您已经发布了一个名为 getContent 的函数,但您将函数调用的结果(不是函数本身)传递给了名为 searchTarget 的 @987654324 @.
  • 另外你不需要在间隔或超时调用setInterval(searchTarget, 13000);

标签: javascript node.js asynchronous puppeteer


【解决方案1】:
  • 您发布了getContent 的定义,而不是searchTarget
  • 您将searchTarget结果传递给setInterval,而不是传递对函数searchTarget 的引用。
  • 您说您遇到了错误,但没有说明这些错误是什么。
  • 可以使用async functionsetInterval
  • 您不需要将awaitconsole.log 一起使用(您不应使用await,因为console.log 不会返回任何内容,更不用说Promise<T>)。

我假设你真正想要的是:

async function getContent() {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto(url);
    const content =  await page.content();
    console.log(content);
    await browser.close();
}

const timerId = window.setInterval( getContent, 13 * 1000 );

// You can call `window.clearInterval( timerId )` to stop the interval loop.

我建议添加错误处理以在第一个错误时停止间隔循环:

/** @type {number} */
let intervalTimerId = null;

async function getContent() {
    try {
        const browser = await puppeteer.launch();
        const page = await browser.newPage();
        await page.goto(url);
        const content =  await page.content();
        await console.log(content);
        await browser.close();
    }
    catch( err ) {
        console.error( "Error in getContent: %o", err );
        if( intervalTimerId ) {
            window.clearInterval( intervalTimerId );
        }
    }
}

intervalTimerId = window.setInterval( getContent, 13 * 1000 );

替代方法:

正如@mplungjan 和@RohanAsokan 等其他用户所指出的那样,您的代码存在潜在的设计问题,因为setInterval 将每13 秒调用一次getContent,即使之前对getContent 的调用仍未完成然而 - 如果(例如)await page.content() 运行时间超过 13 秒,就会发生这种情况。

在这种情况下,解决方案是使用window.setTimeout 而不是window.setInterval 并从getContent 中调用它,如下所示:

/** @type {number} */
let lastSetTimeoutId = null;

async function getContentAndStartLoop() {
    try {
        const browser = await puppeteer.launch();
        const page = await browser.newPage();
        await page.goto(url);
        const content =  await page.content();
        console.log(content);
        await browser.close();

        lastSetTimeoutId = window.setTimeout( getContentAndStartLoop, 13 * 1000 );
    }
    catch( err ) {
        console.error( "Error in getContent: %o", err );
    }
}

请注意,getContentAndStartLoop 将在第一个循环后解决,但会继续运行,直到引发错误。

更好的方法:

我认为最好像这样构造它(使用setTimeoutsetTimeout 适配器,名为delay):

async function myProgram() {
    
    const url     = "https://thispersondoesnotexist.com/":
    const browser = await puppeteer.launch();
    const page    = await browser.newPage();
    
    try {
        while( true ) {
        
            await page.goto( url );
        
            const content = await page.content();
            console.log( content );

            await delay( 13 * 1000 );
        }
    }
    catch( err ) {
        console.error( "Error in myProgram: %o", err );
    }
    finally {
        await browser.close();
    }
    
}

async function delay( ms, state = null ) {
    
    return new Promise( ( resolve, reject ) => {
        window.setTimeout( () => resolve( state ), ms );
    } );
}

【讨论】:

    【解决方案2】:

    我会问你一个问题,你会得到答案。

    如果asyncgetContent() 的请求比13000 毫秒间隔花费的时间更长,您认为会发生什么?

    因此,更好的选择是解决 promise 并按照 cmets 中 @mplungjan 的建议再次调用该函数。

    如果先前的承诺尚未解决,一个可能但不干净的解决方案是清除间隔。

    【讨论】:

    • 我将如何解决承诺并调用函数? (我对 Promise 很陌生)
    • @b0b75 您不需要手动“解决”任何承诺 - 由 await 操作员为您处理。有关示例,请参阅我的更新答案。
    • @Dai 我无法评论您的帖子。但要指出的是,通过重复调用函数并将其设置在无限调用堆栈中,您将失去setInterval 提供的优化优势。 @b0b75 也调查一下。
    • @RohanAsokan “通过重复调用函数并将其设置在无限调用堆栈中” - 请解释您的意思。我不相信我发布的代码中存在堆栈溢出的可能性。如果我的代码有问题,请发表评论回复我的答案,并提供更多详细信息。
    • @rohanAsokan setTimeoutPromise 的使用都没有。无论如何,担心 JS 中的堆栈大小几乎是完全没有必要的——要么你的代码导致无限递归和堆栈溢出,要么它不会。请记住,因为 JS 没有显式的堆栈分配(与 C 不同),所以没有错误的脚本溢出的唯一方法是,如果它正在遍历的数据结构非常大;这在实践中不会发生(因为如果它那么大,你一开始就不会使用 JS)
    猜你喜欢
    • 2017-12-29
    • 2020-01-21
    • 2018-06-26
    • 2021-07-26
    • 2016-08-03
    • 2017-08-23
    • 1970-01-01
    • 2011-11-12
    • 1970-01-01
    相关资源
    最近更新 更多