我正在编写一个node.js应用程序,它允许用户在node.js中生成多页pdf。
我逐个创建页面并将各个页面作为一个数组传递,其中包含从函数到函数的请求,直到创建所有页面,此时我使用pdf merge将多页文档放在一起。
function pdfExport_map(site, siteData, req){
phantom.pdf_export_map(site, siteData, req, pdfExport_census);
}
function pdfExport_census(site, siteData, req){
phantom.pdf_export_census(site, siteData, req, pdfExport_ue);
}
function pdfExport_ue(site, siteData, req){
phantom.pdf_export_ue(site, siteData, req, pdfExport_decay);
}
function pdfExport_decay(site, siteData, req){
phantom.pdf_export_decay(site, siteData, req, processSites);
}
function processSites(req) {
var pdfMerge = new PDFMerge(req.fileStack, 'C:\\Program Files (x86)\\PDFtk\\bin\\pdftk.exe');
var d = Date.now();
var filename = 'r' + d.toString() + '.pdf';
pdfMerge.asNewFile(process.env.FILEPATH + filename).merge(function (error, file) {
console.log(file);
});
}
如果一个用户运行该进程,这非常有效。如果多个用户同时运行该进程,则只有一个用户获得报告。这个过程失败了幻影的承诺。当我在以下函数中设置断点时,我看到在将站点A导出为PDF(断点2)之前,已收到站点B的数据(断点1)。在此阶段,站点B的流程永远不会回升。
function pdf_export_map(site, siteData, req, _pdfExport_census) {
phantom.create()
.then(instance => {
ph = instance;
return instance.createPage();
})
.then(p => {
page = p;
page.open('about:blank');
})
.then(function () {
var renderTimeout,
c = 0;
function doRender() {
console.log('page loaded');
var d = Date.now();
var filename = 'm' + d.toString() + '.pdf';
page.render('tmp/' + filename)
.then(function () {
//breakpoint 2 page PDF export complete
ph.exit();
req.fileStack.push(process.env.FILEPATH + filename);
_pdfExport_census(site, siteData, req)
});
}
page.on('onResourceRequested', function (r) {
c++;
console.log(('000' + r.id).slice(-4) + ' | ' + r.url);
clearTimeout(renderTimeout);
});
page.on('onResourceReceived', function (r) {
if (!r.stage || r.stage === 'end') {
c--;
console.log(('000' + r.id).slice(-4) + ' | ' + r.status);
if (c === 0) {
renderTimeout = setTimeout(doRender, 5000);
}
}
});
if (process.platform == 'win32') {
page.property('paperSize', {
width: '11in',
height: '8.5in'
});
} else {
page.property('paperSize', {
width: '1056px',
height: '816px'
});
}
page.property('viewportSize', {
width: 1056,
height: 816
});
page.property('clipRect', {
top: 0,
left: 0,
width: 1056,
height: 816
});
//breakpoint 1 data received, start render
ejs.renderFile('views/phantommap.ejs', {
site: site,
features: siteData.features,
subdirectory: process.env.SUBDIRECTORY,
page: req.fileStack.length + 1
}, function (err, html) {
page.setContent(html, 'http://' + process.env.HOST + '/amazon/phantommap');
});
})
.catch(err => {
console.log(err);
ph.exit();
});
}
我对幻影和承诺的理解很差。是否可以运行此同步,例如完成一个站点的页面,然后启动第二个报告的页面?
编辑:做了一些测试我评论了ph.exit()。我看到我收到了站点A和站点B的数据。但站点A的页面导出了两次。
编辑:根据Amir的推荐,我通过在函数中声明ph和页面来实现这一点。
phantom.create()
.then(instance => {
_ph = instance;
return instance.createPage();
})
.then(p => {
_page = p;
_page.open('about:blank');
})
.then(function () {
var renderTimeout,
c = 0,
ph = _ph,
page = _page;
我仍然需要研究使用async和await。
答案 0 :(得分:2)
我怀疑您的代码不是线程安全的。我看到你有一个名为ph
的变量。这是一个跨多个请求共享的全局变量吗?如果是这样,那就有问题了。您正在共享实例。相反,您不应该使用任何全局变量并仅为该请求关闭幻像实例。
在https://github.com/amir20/phantomjs-node/issues/583处有关于幽灵的类似问题。但问题在于它正在重复使用幻影过程的实例。
为您的代码提出几点建议。请改用async
和await
。这个回调地狱会让你发疯。对于每个请求,请勿使用在会话外声明的任何全局变量。在请求之间共享数据会产生意外结果。
免责声明:我是PhantomJs-Node的作者。