在NodeJS v10.xx环境中,当尝试通过一些HTML代码创建PDF页面时,每次尝试对其执行某些操作(setCacheEnabled,setRequestInterception等)时,都会遇到关闭页面的问题。 :
async (page, data) => {
try {
const {options, urlOrHtml} = data;
const finalOptions = { ...config.puppeteerOptions, ...options };
// Set caching flag (if provided)
const cache = finalOptions.cache;
if (cache != undefined) {
delete finalOptions.cache;
await page.setCacheEnabled(cache); //THIS LINE IS CAUSING THE PAGE TO BE CLOSED
}
// Setup timeout option (if provided)
let requestOptions = {};
const timeout = finalOptions.timeout;
if (timeout != undefined) {
delete finalOptions.timeout;
requestOptions.timeout = timeout;
}
requestOptions.waitUntil = 'networkidle0';
if (urlOrHtml.match(/^http/i)) {
await page.setRequestInterception(true); //THIS LINE IS CAUSING ERROR DUE TO THE PAGE BEING ALREADY CLOSED
page.once('request', request => {
if(finalOptions.method === "POST" && finalOptions.payload !== undefined) {
request.continue({method: 'POST', postData: JSON.stringify(finalOptions.payload)});
}
});
// Request is for a URL, so request it
await page.goto(urlOrHtml, requestOptions);
}
return await page.pdf(finalOptions);
} catch (err) {
logger.info(err);
}
};
我在某个地方读到,这个问题可能是由于缺少一些等待而引起的,但这与我的情况不符。
我不是直接使用puppeteer,而是这个在其上创建集群并处理进程的库:
答案 0 :(得分:1)
我明白了。
我确实忘记了等待我发布的函数的调用。
该呼叫位于我用于创建集群实例的另一个文件中:
async function createCluster() {
//We will protect our app with a Cluster that handles all the processes running in our headless browser
const cluster = await Cluster.launch({
concurrency: Cluster[config.cluster.concurrencyModel],
maxConcurrency: config.cluster.maxConcurrency
});
// Event handler to be called in case of problems
cluster.on('taskerror', (err, data) => {
console.log(`Error on cluster task... ${data}: ${err.message}`);
});
// Incoming task for the cluster to handle
await cluster.task(async ({ page, data }) => {
main.postController(page, data); // <-- I WAS MISSING A return await HERE
});
return cluster;
}
答案 1 :(得分:1)
您已经给出了解决方案,但是由于这是库的一个常见问题(我是作者),所以我想提供更多的见解。
当作业排队并准备好执行时,puppeteer-cluster将创建一个页面,并使用创建的cluster.task
对象和排队的数据调用任务函数(赋予page
) 。然后,群集将等待直到Promise完成(已实现或被拒绝),然后将关闭页面并执行队列中的下一个作业。
当异步函数隐式创建Promise时,这意味着给cluster.task
函数提供的异步函数完成后,页面将关闭。确定该页面将来是否可以使用没有神奇的事情。
下面是一个带有常见错误的代码示例。用户可能希望在关闭页面之前等待外部事件,如下面的示例(不起作用)所示:
非工作(!)代码示例:
await cluster.task(async ({ page, data }) => {
await page.goto('...');
setTimeout(() => { // user is waiting for an asynchronous event
await page.evaluate(/* ... */); // Will throw an error as the page is already closed
}, 1000);
});
在此代码中,页面已在执行异步功能之前关闭。纠正此问题的方法将是返回一个Promise。
工作代码示例:
await cluster.task(async ({ page, data }) => {
await page.goto('...');
// will wait until the Promise resolves
await new Promise(resolve => {
setTimeout(() => { // user is waiting for an asynchronous event
try {
await page.evalute(/* ... */);
resolve();
} catch (err) {
// handle error
}
}, 1000);
});
});
在此代码示例中,任务功能等待,直到内部承诺被解析,直到其解析功能为止。这将使页面保持打开状态,直到异步函数调用resolve
。此外,代码使用try..catch
块,因为该库无法捕获异步代码块内引发的事件。