![](/img/trans.png)
[英]node.js application - how to connect to mongodb and “share” connection via an include?
[英]Node.js: share connection object throughout the application
我在使用 puppeteer 实现generic-pool
时遇到问题。 以下是我的相关代码部分。
更新
感谢@Jacob 的帮助,我对这个概念及其工作原理更加清楚,并且代码也更具可读性和清晰性。 我仍然遇到在每个请求上都创建通用池的问题。 我如何确保每次都使用相同的通用池而不是创建新池
浏览器-pool.js
const genericPool = require('generic-pool');
const puppeteer = require('puppeteer');
class BrowserPool {
static async getPool() {
const browserParams = process.env.NODE_ENV == 'development' ? {
headless: false,
devtools: false,
executablePath: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'
}
:
{
headless: true,
devtools: false,
executablePath: 'google-chrome-unstable',
args: ['--no-sandbox', '--disable-dev-shm-usage']
};
const factory = {
create: function() {
return puppeteer.launch(browserParams);
},
destroy: function(instance) {
console.log('closing browser in hrere.....');
instance.close();
}
};
const opts = {
max: 5
};
this.myBrowserPool = genericPool.createPool(factory, opts);
}
static async returnPool() {
if (this.myBrowserPool == "") {
getPool();
}
return this.myBrowserPool.acquire();
}
}
BrowserPool.myBrowserPool = null;
module.exports = BrowserPool;
进程-export.js
const BrowserPool = require('./browser-pool');
async function performExport(params){
const myPool = BrowserPool.getPool();
const resp = BrowserPool.myBrowserPool.acquire().then(async function(client){
try {
const url = config.get('url');
const page = await client.newPage();
await page.goto(url, {waitUntil: ['networkidle2', 'domcontentloaded']});
let gotoUrl = `${url}/dashboards/${exportParams.dashboardId}?csv_export_id=${exportParams.csvExportId}`;
//more processing
await page.goto(gotoUrl, {waitUntil: 'networkidle2' })
await myPool().myBrowserPool.release(client);
return Data;
} catch(err) {
try {
const l = await BrowserPool.myBrowserPool.destroy(client);
} catch(e) {
}
return err;
}
}).catch(function(err) {
return err;
});
return resp;
}
module.exports.performExport = performExport;
我的理解是
1)当应用程序启动时,我可以启动例如2 chromium
实例,然后当我想访问一个页面时,我可以使用两个连接中的任何一个,因此浏览器基本上是打开的,我们提高了性能,因为浏览器启动可以慢慢来。 这个对吗?
2)我在哪里放置acquire()
代码,我知道这应该在app.js
中,所以我们在应用程序启动时获取实例,但是我的pupeteer代码在不同的文件中,我如何通过浏览器在包含我的 pupeteer 代码的文件中引用。
当我使用上面的代码时,每次都会启动一个新的浏览器实例,并且不考虑max
属性,它会打开请求的多个实例。
我很抱歉,如果它非常考验,我可能没有完全理解这个概念。 澄清这一点的任何帮助都会非常有帮助。
使用池时,您需要使用.acquire()
来获取 object,然后在完成后使用 .release( .release()
,以便将 object 返回到池中并提供给其他东西。 如果不使用.release()
,您可能根本就没有池。 我喜欢在池中使用这个辅助模式:
class BrowserPool {
// ...
static async withBrowser(fn) {
const pool = BrowserPool.myBrowserPool;
const browser = await pool.acquire();
try {
await fn(browser);
} finally {
pool.release(browser);
}
}
}
这可以像这样在代码中的任何地方使用:
await BrowserPool.withBrowser(async browser => {
await browser.doSomeThing();
await browser.doSomeThingElse();
});
关键是finally
子句确保无论您的任务完成还是抛出错误,您每次都会干净地将浏览器释放回池中。
听起来您可能也向后考虑了max
选项的概念,并且期望浏览器实例被生成到max
。 相反, max
的意思是“只创建max
数量的资源”。 例如,如果您尝试在没有释放任何内容的情况下获取第六个资源,则acquire(...)
调用将阻塞,直到一个项目返回到池中。
另一方面, min
选项的意思是“始终至少保留这么多物品”,您可以使用它来预先分配资源。 如果要提前创建 5 个项目,请将min
设置为 5。如果要创建 5 个项目并且只创建 5 个项目,请将min
和max
都设置为 5。
更新:
我注意到在您的原始代码中,您会在出现错误时销毁并在没有错误时释放。 仍然希望像我的一样使用包装器 function 来集中所有资源获取/释放逻辑(SRP 方法)的好处。 以下是如何更新它以自动销毁错误:
class BrowserPool {
// ...
static async withBrowser(fn) {
const pool = BrowserPool.myBrowserPool;
const browser = await pool.acquire();
try {
await fn(browser);
pool.release(browser);
} catch (err) {
await pool.destroy(browser);
throw err;
}
}
}
附录
如果您采用异步 function 而不是混合异步 function 内容和 Promise 回调内容,那么弄清楚代码中发生了什么会更容易。 下面是如何重写它:
async function performExport(params){
const myPool = BrowserPool.myBrowserPool;
const client = await myPool.acquire();
try {
const url = config.get('url');
const page = await client.newPage();
await page.goto(url, {waitUntil: ['networkidle2', 'domcontentloaded']});
let gotoUrl = `${url}/dashboards/${exportParams.dashboardId}?csv_export_id=${exportParams.csvExportId}`;
//more processing
await page.goto(gotoUrl, {waitUntil: 'networkidle2' })
await myPool.release(client);
return Data;
} catch(err) {
try {
const l = await myPool.destroy(client);
} catch(e) {
}
return err; // Are you sure you want to do this? Would suggest throw err.
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.