ts中异步等待目标生成的办法

本文介绍了一种使用async, promise及setTimeout实现异步等待的方法,通过定义asyncCheck函数,可按指定检查粒度和超时时间监测对象生成状态,直至生成完成返回对象,适用于前端异步操作场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

async,promise,setimeout配合就行。其它有sleep的语言更简单

/**
     * 异步等待对象的生成,对象生成完成返回生成的对象
     * @param getter 对象的获取函数
     * @param checkSize 检查粒度,ms
     * @param timeout 超时时间, ms
     */
export const asyncCheck = async<T> (getter: () => T, checkSize = 100, timeout = 1000) => {
    return new Promise<T>(x => {
        const check = (num = 0) => {
            const target = getter();
            if (target !== undefined && target !== null) {
                x(target)
            } else if (num > timeout / checkSize) {// 超时
                x(target)
            } else {
                setTimeout(() => check(++num), checkSize);
            }
        };
        check();
    });
}
let input = await asyncCheck(() => document.querySelector("#input"));
<think>我们正在讨论在NestJS项目中集成Puppeteer。用户提供了多个引用,其中引用[1]提到Node.js适合实时应用,但不适合CPU密集型任务;引用[2][3]提到了关于政采云前端团队的系列分享,其中包括爬虫实战和Node性能优化;引用[4]提供了一些NodeJs爬虫源码,包括使用puppeteer的例子。用户的问题:如何在NestJS中使用Puppeteer实现网页抓取或自动化任务?由于NestJS是一个基于Node.js的后端框架,而Puppeteer是一个Node库,用于控制无头浏览器,我们可以按照以下步骤进行:1.创建或进入现有的NestJS项目。2.安装Puppeteer依赖。3.创建一个服务(Service)来封装Puppeteer操作。4.在需要的地方(如控制器)使用这个服务。注意:Puppeteer在安装时会下载一个Chromium,这可能会在服务器上引起问题(比如在无头服务器环境中)。另外,Puppeteer比较消耗资源,需要注意管理浏览器实例,避免创建过多实例。参考引用[4]中的示例,其中使用了puppeteer和nodeJs,我们可以模仿其思想。步骤:1.安装Puppeteer:```bashnpminstallpuppeteer```2.生成一个服务模块(如果还没有):```bashnestgenerateservicepuppeteer```3.在生成的服务中,编写使用Puppeteer的代码。注意:由于Puppeteer启动浏览器是一个异步过程,并且可能抛出异常,需要妥善处理。4.我们可以创建一个启动浏览器的函数,并实现页面截图、数据提取等操作。5.在控制器中调用该服务。示例代码:在`puppeteer.service.ts`中:```typescriptimport{Injectable}from'@nestjs/common';import*aspuppeteerfrom'puppeteer';@Injectable()exportclassPuppeteerService{asyncscrape(url:string):Promise<string>{constbrowser=awaitpuppeteer.launch();constpage=awaitbrowser.newPage();awaitpage.goto(url);constcontent=awaitpage.content();//获取页面HTML内容awaitbrowser.close();returncontent;}//或者更复杂的操作,例如模拟登录asyncloginAndGetData(url:string,username:string,password:string):Promise<any>{constbrowser=awaitpuppeteer.launch();constpage=awaitbrowser.newPage();awaitpage.goto(url);//假设登录表单的输入框选择器和提交按钮选择器awaitpage.type('#username',username);awaitpage.type('#password',password);awaitpage.click('#submit');//等待导航到新页面awaitpage.waitForNavigation();//现在可以获取登录后的页面内容constcontent=awaitpage.content();awaitbrowser.close();returncontent;}}```在控制器中,我们可以这样使用:```typescriptimport{Controller,Get}from'@nestjs/common';import{PuppeteerService}from'./puppeteer.service';@Controller('scrape')exportclassScrapeController{constructor(privatereadonlypuppeteerService:PuppeteerService){}@Get()asyncscrape(){constdata=awaitthis.puppeteerService.scrape('https://example.com');returndata;}}```注意:上面的例子是每次请求都启动一个浏览器,然后关闭。这在高并发下可能会成为性能瓶颈。因此,通常我们会考虑复用浏览器实例,或者使用连接池等优化方法。另外,由于启动浏览器比较慢,所以也可以考虑在应用启动时就启动一个浏览器,然后作为单例在整个应用中共享。但是要注意,共享的浏览器实例可能会同时处理多个页面,这需要确保每个页面操作是隔离的。参考引用[2][3][4]中提到的关于Node性能优化的内容,以及爬虫实战,我们可以知道在高负载下需要优化。比如,使用`puppeteer-cluster`来管理多个浏览器实例,或者使用`browserless`这样的无头浏览器托管服务,避免在应用本地启动浏览器。另外,引用[3]提到“Node性能优化:我是如何懵逼应对Node定时批量任务爆栈的”,这提醒我们在编写定时任务时要注意内存泄漏和栈溢出问题。相关问题:1.如何在NestJS中复用Puppeteer的浏览器实例?2.如何避免Puppeteer在高并发场景下的性能问题?3.Puppeteer在NestJS中除了爬虫还能做什么自动化任务?4.如何用Puppeteer进行网页截图并保存到本地或云存储?</think> 在 NestJS 项目中集成和使用 Puppeteer 实现网页抓取或自动化任务,可以按照以下步骤操作: ### 一、安装 Puppeteer 依赖 ```bash npm install puppeteer ``` ### 二、创建 Puppeteer 服务(核心功能封装) ```typescript // src/puppeteer/puppeteer.service.ts import { Injectable } from '@nestjs/common'; import * as puppeteer from 'puppeteer'; @Injectable() export class PuppeteerService { private browser: puppeteer.Browser; // 初始化浏览器实例 async initBrowser() { this.browser = await puppeteer.launch({ headless: true, // 无头模式(生产环境推荐) args: ['--no-sandbox', '--disable-setuid-sandbox'], // Docker 环境必需参数 }); } // 创建新页面 async createPage() { if (!this.browser) await this.initBrowser(); return await this.browser.newPage(); } /** * 网页抓取方法 * @param url 目标网址 * @param waitForSelector 等待元素选择器(可选) */ async scrapePage(url: string, waitForSelector?: string) { const page = await this.createPage(); try { await page.goto(url, { waitUntil: 'networkidle2', timeout: 60000 }); if (waitForSelector) { await page.waitForSelector(waitForSelector, { timeout: 30000 }); } // 获取页面内容 const content = await page.content(); // 获取特定数据(示例) const title = await page.title(); const metaDescription = await page.$eval('meta[name="description"]', el => el.content); return { title, metaDescription, html: content }; } finally { await page.close(); // 确保页面关闭 } } // 关闭浏览器(应用退出时调用) async closeBrowser() { if (this.browser) await this.browser.close(); } } ``` ### 三、在模块中注册服务 ```typescript // src/puppeteer/puppeteer.module.ts import { Module } from '@nestjs/common'; import { PuppeteerService } from './puppeteer.service'; @Module({ providers: [PuppeteerService], exports: [PuppeteerService], // 导出以便其他模块使用 }) export class PuppeteerModule {} // 在AppModule中导入 import { PuppeteerModule } from './puppeteer/puppeteer.module'; @Module({ imports: [PuppeteerModule], // ... }) export class AppModule {} ``` ### 四、在控制器中使用(示例) ```typescript // src/scraper/scraper.controller.ts import { Controller, Get } from '@nestjs/common'; import { PuppeteerService } from '../puppeteer/puppeteer.service'; @Controller('scrape') export class ScraperController { constructor(private readonly puppeteerService: PuppeteerService) {}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值