Node.js 如何对在GraphQL中创建headless Chrome实例的函数的多个调用进行分组
我有一个运行GraphQL的NodeJS服务器。我的一个查询从API获取“项目”列表并返回URL。这个URL然后被传递给另一个函数,该函数获取该网站的屏幕截图(使用一个NodeJS包,它是Puppeter的包装器) 我的问题是,当我运行这个程序时,如果有更多的项目需要去做,并为它生成一个屏幕截图。它为每个数据响应对象运行屏幕截图功能(见下文),因此在服务器上创建了一个单独的无头浏览器,因此我的服务器很快就会耗尽内存并崩溃Node.js 如何对在GraphQL中创建headless Chrome实例的函数的多个调用进行分组,node.js,graphql,puppeteer,Node.js,Graphql,Puppeteer,我有一个运行GraphQL的NodeJS服务器。我的一个查询从API获取“项目”列表并返回URL。这个URL然后被传递给另一个函数,该函数获取该网站的屏幕截图(使用一个NodeJS包,它是Puppeter的包装器) 我的问题是,当我运行这个程序时,如果有更多的项目需要去做,并为它生成一个屏幕截图。它为每个数据响应对象运行屏幕截图功能(见下文),因此在服务器上创建了一个单独的无头浏览器,因此我的服务器很快就会耗尽内存并崩溃 { "data": { "projects": [
{
"data": {
"projects": [
{
"screenshot": {
"url": "https://someurl.com/randomid/screenshot.png"
}
},
{
"screenshot": {
"url": "https://someurl.com/randomid/screenshot.png"
}
}
]
}
}
这是我为上下文的屏幕截图逻辑编写的代码的简化版本:
const webshotScreenshot = (title, url) => {
return new Promise(async (resolve, reject) => {
/** Create screenshot options */
const options = {
height: 600,
scaleFactor: 2,
width: 1200,
launchOptions: {
headless: true,
args: ['--no-sandbox']
}
};
/** Capture website */
await captureWebsite.base64(url.href, options)
.then(async response => {
/** Create filename and location */
let folder = `output/screenshots/${_.kebabCase(title)}`;
/** Create directory */
createDirectory(folder);
/** Create filename */
const filename = 'screenshot.png';
const fileOutput = `${folder}/${filename}`;
return await fs.writeFile(fileOutput, response, 'base64', (err) => {
if (err) {
// handle error
}
/** File saved successfully */
resolve({
fileOutput
});
});
})
.catch(err => {
// handle error
});
});
};
我想知道的是,我如何修改这个逻辑,以:
const DataLoader = require('dataloader')
const screenshotLoader = new DataLoader(async (urls) => {
// see below
})
// Inject a new DataLoader instance into your context, then inside your resolver
screenshotLoader.load(yourUrl)
它看起来不像捕获网站
支持传递多个URL。这意味着,每次调用captureWebsite.base64都会启动一个新的木偶玩家实例。所以,Promise.all
已退出,但您有两个选择:
bluebird
或类似库并行运行请求,但有一定限制:const DataLoader = require('dataloader')
const screenshotLoader = new DataLoader(async (urls) => {
// see below
})
// Inject a new DataLoader instance into your context, then inside your resolver
screenshotLoader.load(yourUrl)
const images = []
for (const url in urls) {
const image = await captureWebsite.base64(url, options)
images.push(image)
}
return images
const concurrency = 3 // 3 at a time
return Bluebird.map(urls, (url) => {
return captureWebsite.base64(url, options)
}, { concurrency })
const browser = await puppeteer.launch({args: ['--no-sandbox', '--disable-setuid-sandbox']});
const page = await browser.newPage();
for (const url in urls) {
const image = await captureWebsite.base64(url, options)
await page.goto(url);
await page.screenshot(/* path and other screenshot options */);
}
await browser.close();