如何限制Express.js的调用次数?
How to limit the number of calls in Express.js?
我正在使用 express 显示通过 puppeteer 进行网络抓取的结果,但我遇到了性能问题。
我多次调用爬虫文件,因为我想一次获得多个结果。
例如:
const express = require('express')
const app = express()
const scraper = require('./scrapers/scraper.js');
app.get('/getResults', function(req, res, next) {
const url = 'http://www.example.com';
const val1 = new Promise((resolve, reject) => {
scraper
.getPrice(results, url, nights)
.then(data => {
resolve(data)
})
.catch(err => reject('Medium scrape failed'))
})
const url = 'http://www.example.com';
const val2 = new Promise((resolve, reject) => {
scraper
.getPrice(results, url, nights)
.then(data => {
resolve(data)
})
.catch(err => reject('Medium scrape failed'))
const url = 'http://www.example.com';
const val3 = new Promise((resolve, reject) => {
scraper
.getPrice(results, url, nights)
.then(data => {
resolve(data)
})
.catch(err => reject('Medium scrape failed'))
const url = 'http://www.example.com';
const val4 = new Promise((resolve, reject) => {
scraper
.getPrice(results, url, nights)
.then(data => {
resolve(data)
})
.catch(err => reject('Medium scrape failed'))
Promise.all([val1, val2, val3, val4])
.then(data => {
console.log(data)
})
.catch(err => res.status(500).send(err))
}
上面的代码将一次调用 scraper.js 文件 4 次,但是我应该怎么做才能在前一个完成后调用每个文件?我的意思是,当 val1 完成时,它应该 运行 val2 等等。
事实上,我的代码调用了 scraper 文件 18 次,这对计算机性能不利,因为 puppeteer 是基于 Chromium 的,它确实会一次打开一个新的 Chromium 实例 18 次。
我什至在 运行 时遇到此错误:
(node:26600) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 exit listeners added. Use emitter.setMaxListeners() to increase limit
你知道 promise 可以顺序进行吗?
val1.then(v1 => return val2).then(v2=> {...})
您应该打开一个新的 Chromium 选项卡,而不是实例。 (你是不是混淆了概念?)
最重要的是 - 您需要更好地管理下载过程。队列将是最好的。它可以是一个简单的:确保不超过 n
个进程 运行 或更高级:监视服务器资源。
您或许可以找到一些包裹。如果没有适合您的,请记住在出现问题时处理这种情况,Node 不会注意到进程结束。
我交替使用方法:
- 将 URL 标记为正在下载,如果在给定时间内未检索到,则将其 returns 放入队列(更具体地说:指定何时重新下载 URL .下载时+1分钟,下载后例如1个月)
- 我保存下载过程的 PID 并定期检查它是否正常工作
还有rate-limits
控制HTTP调用的次数。在端点上,关于IP同时下单的数量。
异步等待
您可以使用 async await 编写代码。有趣的是,您可以处理所有错误,并通过 promises 自动返回值。
app.get('/getResults', async function(req, res, next) { //<-- notice the async here
try{
const val1 = await scraper.getPrice(results, url, nights)
const val2 = await scraper.getPrice(results, url, nights)
const val3 = await scraper.getPrice(results, url, nights)
const val4 = await scraper.getPrice(results, url, nights)
return res.send([val1, val2, val3, val4])
} catch(err) {
res.status(500).send(err)
}
})
p-极限
您可以使用名为 p-limit
的包,其中 运行 具有有限并发性的多个承诺返回和异步函数。
const pLimit = require('p-limit');
const limit = pLimit(1);
const input = [
limit(() => scraper.getPrice(results, url, nights)),
limit(() => scraper.getPrice(results, url, nights)),
limit(() => scraper.getPrice(results, url, nights))
];
(async () => {
// Only one promise is run at once
const result = await Promise.all(input);
console.log(result);
})();
for..of 循环
您可以优化这些代码并减少代码重复。使用 async..await 和 for..of,您可以进一步减少代码,
// assuming you have these urls
const urls = [
'http://example.com', 'http://example.com', 'http://example.com'
];
const results = []
for(let url of urls){
const data = await scraper.getPrice(results, url, nights);
results.push(data)
}
console.log(results)
我正在使用 express 显示通过 puppeteer 进行网络抓取的结果,但我遇到了性能问题。
我多次调用爬虫文件,因为我想一次获得多个结果。
例如:
const express = require('express')
const app = express()
const scraper = require('./scrapers/scraper.js');
app.get('/getResults', function(req, res, next) {
const url = 'http://www.example.com';
const val1 = new Promise((resolve, reject) => {
scraper
.getPrice(results, url, nights)
.then(data => {
resolve(data)
})
.catch(err => reject('Medium scrape failed'))
})
const url = 'http://www.example.com';
const val2 = new Promise((resolve, reject) => {
scraper
.getPrice(results, url, nights)
.then(data => {
resolve(data)
})
.catch(err => reject('Medium scrape failed'))
const url = 'http://www.example.com';
const val3 = new Promise((resolve, reject) => {
scraper
.getPrice(results, url, nights)
.then(data => {
resolve(data)
})
.catch(err => reject('Medium scrape failed'))
const url = 'http://www.example.com';
const val4 = new Promise((resolve, reject) => {
scraper
.getPrice(results, url, nights)
.then(data => {
resolve(data)
})
.catch(err => reject('Medium scrape failed'))
Promise.all([val1, val2, val3, val4])
.then(data => {
console.log(data)
})
.catch(err => res.status(500).send(err))
}
上面的代码将一次调用 scraper.js 文件 4 次,但是我应该怎么做才能在前一个完成后调用每个文件?我的意思是,当 val1 完成时,它应该 运行 val2 等等。
事实上,我的代码调用了 scraper 文件 18 次,这对计算机性能不利,因为 puppeteer 是基于 Chromium 的,它确实会一次打开一个新的 Chromium 实例 18 次。
我什至在 运行 时遇到此错误:
(node:26600) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 exit listeners added. Use emitter.setMaxListeners() to increase limit
你知道 promise 可以顺序进行吗?
val1.then(v1 => return val2).then(v2=> {...})
您应该打开一个新的 Chromium 选项卡,而不是实例。 (你是不是混淆了概念?)
最重要的是 - 您需要更好地管理下载过程。队列将是最好的。它可以是一个简单的:确保不超过 n
个进程 运行 或更高级:监视服务器资源。
您或许可以找到一些包裹。如果没有适合您的,请记住在出现问题时处理这种情况,Node 不会注意到进程结束。
我交替使用方法:
- 将 URL 标记为正在下载,如果在给定时间内未检索到,则将其 returns 放入队列(更具体地说:指定何时重新下载 URL .下载时+1分钟,下载后例如1个月)
- 我保存下载过程的 PID 并定期检查它是否正常工作
还有rate-limits
控制HTTP调用的次数。在端点上,关于IP同时下单的数量。
异步等待
您可以使用 async await 编写代码。有趣的是,您可以处理所有错误,并通过 promises 自动返回值。
app.get('/getResults', async function(req, res, next) { //<-- notice the async here
try{
const val1 = await scraper.getPrice(results, url, nights)
const val2 = await scraper.getPrice(results, url, nights)
const val3 = await scraper.getPrice(results, url, nights)
const val4 = await scraper.getPrice(results, url, nights)
return res.send([val1, val2, val3, val4])
} catch(err) {
res.status(500).send(err)
}
})
p-极限
您可以使用名为 p-limit
的包,其中 运行 具有有限并发性的多个承诺返回和异步函数。
const pLimit = require('p-limit');
const limit = pLimit(1);
const input = [
limit(() => scraper.getPrice(results, url, nights)),
limit(() => scraper.getPrice(results, url, nights)),
limit(() => scraper.getPrice(results, url, nights))
];
(async () => {
// Only one promise is run at once
const result = await Promise.all(input);
console.log(result);
})();
for..of 循环
您可以优化这些代码并减少代码重复。使用 async..await 和 for..of,您可以进一步减少代码,
// assuming you have these urls
const urls = [
'http://example.com', 'http://example.com', 'http://example.com'
];
const results = []
for(let url of urls){
const data = await scraper.getPrice(results, url, nights);
results.push(data)
}
console.log(results)