简体   繁体   中英

Nested classes instances in Javascript/Node.js

I'm using puppeteer which is a NodeJS module that controls chrome.

It has 2 functions to initiate a new browser and a new page.

const browser = await puppeteer.launch() and browser.newPage()

I want to create a class for creating a new page and new browser.

This is the old way I was doing it, without classes, it works but it doesn't allow me to create new pages. This is why I want to move to using classes.

let chrome = {}

chrome.init = async (options) => {
    chrome.browser = await puppeteer.launch(options)
    chrome.page = await chrome.browser.newPage()   
}

chrome.pageContains = async (string) => {

    return await chrome.page.evaluate( (string) => {

        const regex = new RegExp(string, 'i')

        return regex.test( document.querySelector('body').innerText )

    }, string)
}

module.exports = chrome

Here's my new code but I have no idea what I'm doing, it's obviously wrong and makes no sense.

chrome.init = async (options) => {
    return {browser: await new Chrome(options)
}

class Chrome {
    async constructor(options) {
        this.browser = await puppeteer.launch(options)
    }

    newPage() {
        return await this.browser.newPage()
    }
}

class Page {
    async constructor() {
        this.page = await chrome.browser.newPage()
    }

}

So how do I make my old code work using classes instead of an object?

You have some typo and constructors are not async.

Other than that, you simply have to pass the right browser function to the Page class. You can extend Chrome with page and use super , or keep them separate, but the page must have access to the browser at some point.

First, we will launch the browser, and return it. Await will take care of promises.

const puppeteer = require('puppeteer');

class Chrome {
    constructor(options) {
        this.browser = puppeteer.launch(options);
        return this.browser;
    }
}

Then we pass it to the page constructor and use it from there.

class Page {
    constructor(browser) {
        this.browser = browser;
        this.page = browser.newPage();
        return this.page;
    }

    async pageContains(string){
        return await this.browser.page.evaluate( (string) => {
            const regex = new RegExp(string, 'i')
            return regex.test( document.querySelector('body').innerText )
        }, string)
    }
}

Then, we call them and make them usable. And return the browser and page object if needed.

const getChrome = async (options) => {
    const browser = await new Chrome(options);
    const page = await new Page(browser);
    return { browser, page }
}

Now we can use them.

(async ()=>{
    const page = (await getChrome({headless: false})).page;
    await page.goto('http://example.com');
})()

I am pretty sure it can be refactored and what I wrote here is not the best practice, but this will get you going.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM