如何使用具有设定间隔的异步函数

b0b*_*b75 5 javascript asynchronous node.js puppeteer

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);

Run Code Online (Sandbox Code Playgroud)

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

Dai*_*Dai 5

  • 您已经发布了 的定义getContent,而不是searchTarget
  • 您传递的是to的结果,而不是传递对 function 的引用。searchTargetsetIntervalsearchTarget
  • 您说您遇到了错误,但没有说明这些错误是什么。
  • 可以使用async functionwith setInterval
  • 您不需要使用awaitwith console.log(您不应该使用await,因为 asconsole.log不会返回任何内容,更不用说 a 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.
Run Code Online (Sandbox Code Playgroud)

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

/** @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 );
Run Code Online (Sandbox Code Playgroud)

替代方法:

正如 @mplungjan 和 @RohanAsokan 等其他用户指出的那样,您的代码存在潜在的设计问题,因为即使之前的调用尚未完成,setInterval也会每 13 秒调用一次 - 如果(例如)花费更长的时间,则可能会发生这种情况运行时间少于 13 秒。getContentgetContentawait page.content()

在这种情况下,解决方案是使用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 );
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,getContentAndStartLoop它将在第一个循环后解析,但会继续运行,直到抛出错误。

更好的方法:

我认为最好像这样构造它(使用 -adapterPromise命名setTimeoutdelay

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 );
    } );
}
Run Code Online (Sandbox Code Playgroud)