Javascript 如何使用makepdf将web worker应用于PDF的呈现

Javascript 如何使用makepdf将web worker应用于PDF的呈现,javascript,pdf,web-worker,pdfmake,Javascript,Pdf,Web Worker,Pdfmake,我使用JavaScript插件()成功地创建了一个PDF,非常棒。 但是,当我尝试渲染约8000行的库存/分类账打印输出时,它会冻结超过一分钟 这是我通常声明docDefinition的方式 var docDefinition = { pageOrientation: orientation, footer: function(currentPage, pageCount) { return {text: currentPage.toString() + ' / ' + pageCount,

我使用JavaScript插件()成功地创建了一个PDF,非常棒。 但是,当我尝试渲染约8000行的库存/分类账打印输出时,它会冻结超过一分钟

这是我通常声明docDefinition的方式

var docDefinition = { 
pageOrientation: orientation, 
footer: function(currentPage, pageCount) { return {text: currentPage.toString() + ' / ' + pageCount, fontSize:8, alignment:'center'}; }, 
content:[ 
   printHeader, 
  { fontSize: 8, alignment: 'right', style: 'tableExample', 
   table: { 
       widths: width, 
       headerRows: 1, body: arr }, 
   layout: 'lightHorizontalLines' }] }
在哪里

var printHeader =   [ { text: 'COMPANY NAME',alignment:'center' },
{ text: 'Address 1',alignment:'center' },
{ text: 'Address 2',alignment:'center' },
{ text: 'Additional Details,alignment:'center' },
{ text: 'document title',alignment:'center' }];

生成

我搜索了web workers,发现它可以解决这个UI冻结问题。 所以我尝试为它创建一个web worker:

$('#makepdf').click(function(){
    var worker = new Worker("<?php echo URL::to('/'); ?>/js/worker.js");
  worker.addEventListener('message',function(e){
  console.log('Worker said: ',e.data);
},false);

worker.postMessage(docDefinition);
来自控制台.log()的输出

工人说:对象{pageOrientation:“肖像”,内容:数组[7]} 它正确地记录了json结构

到目前为止还不错。 但是在我向worker添加了
pdfmake.min.js
vfs_font.js
之后,我得到了错误
Uncaught TypeError:无法读取未定义的属性'createElements'

我甚至在开始使用worker之前就发现了错误


是否可以使用pdfmake插件实现web工作人员?

简单答案

只需提供一个虚拟构造函数:

var document = { 'createElementNS': function(){ return {} } };
var window = this;
importScripts( 'pdfmake.min.js', 'vfs_fonts.js' );
或者,如果您认为它太脏,请导入(仅60k)并为其创建一个虚拟文档


解释

已知pdfmake与工人在一起

pdfmake本身创建元素。 不过,它的缩小脚本确实如此,显然是为了创建一个下载链接

无论如何,我们不需要下载链接,所以只要给它一个虚拟链接就可以了(现在)

如果将来它需要一个真正的DOM, 坏消息是文档在web worker中。 好消息是我们有一个纯javascript实现。 XML-JS, 提取并查找
tinyxmlw3cdom.js
, 导入它,您可以创建一个功能文档

除了文档之外,由于通过
window
变量获取pdfmake,我们需要引入window作为全局变量的别名

对我来说,这些步骤使pdfmake在web worker中工作

要保存该文件,您需要将pdfmake提供的base64数据转换为二进制下载。 有许多脚本可用,例如。 在下面的代码中,我正在使用


代码

我的工人是一个可以缓存的工人。 如果您在服务器端组成worker, 您可以去掉堆栈和构建函数,直接调用pdfmake, 使这两个js代码更加简单

主HTML:

<script src='FileSaver.min.js'></script>
<script>
function base64ToBlob( base64, type ) {
    var bytes = atob( base64 ), len = bytes.length;
    var buffer = new ArrayBuffer( len ), view = new Uint8Array( buffer );
    for ( var i=0 ; i < len ; i++ )
      view[i] = bytes.charCodeAt(i) & 0xff;
    return new Blob( [ buffer ], { type: type } );
}
//////////////////////////////////////////////////////////

var pdfworker = new Worker( 'worker.js' );

pdfworker.onmessage = function( evt ) {
   // open( 'data:application/pdf;base64,' + evt.data.base64 ); // Popup PDF
   saveAs( base64ToBlob( evt.data.base64, 'application/pdf' ), 'General Ledger.pdf' );
};

function pdf( action, data ) {
   pdfworker.postMessage( { action: action, data: data } );
}

pdf( 'add', 'Hello WebWorker' );
pdf( 'add_table', { headerRows: 1 } );
pdf( 'add', [ 'First', 'Second', 'Third', 'The last one' ] );
pdf( 'add', [ { text: 'Bold value', bold: true }, 'Val 2', 'Val 3', 'Val 4' ] );
pdf( 'close_table' );
pdf( 'add', { text: 'This paragraph will have a bigger font', fontSize: 15 } );
pdf( 'gen_pdf' ); // Triggers onmessage when it is done

// Alternative, one-size-fit-all usage
pdf( 'set', { pageOrientation: 'landscape', footer: { text: 'copyright 2015', fontSize: 8, alignment:'center'}, content:[ "header", { fontSize: 8, alignment: 'right', table: { headerRows: 1, body: [[1,2,3],[4,5,6]] } }] } );
pdf( 'gen_pdf' );

</script>

函数base64ToBlob(base64,类型){
var bytes=atob(base64),len=bytes.length;
var buffer=new ArrayBuffer(len),view=new Uint8Array(buffer);
对于(变量i=0;i
工人:

//importScripts( 'tinyxmlw3cdom.js' );
//var document = new DOMDocument( new DOMImplementation() );
var document = { 'createElementNS': function(){ return {} } };
var window = this;
importScripts( 'pdfmake.min.js', 'vfs_fonts.js' );

(function() { 'use strict';

var doc, current, context_stack;

function set ( data ) {
   doc = data;
   if ( ! doc.content ) doc.content = [];
   current = doc.content;
   context_stack = [ current ];
}
set( {} );

function add ( data ) {
   current.push( data );
}

function add_table ( template ) {
   if ( ! template ) template = {};
   if ( ! template.table ) template = { table: template };
   if ( ! template.table.body ) template.table.body = [];
   current.push( template ); // Append table
   push( template.table.body ); // Switch context to table body
}

function push ( data ) {
   context_stack.push( current );
   return current = data;
}

function pop () {
   if ( context_stack.length <= 1 ) return console.warn( "Cannot close pdf root" );
   context_stack.length -= 1;
   return current = context_stack[ context_stack.length-1 ];
}

function gen_pdf() {
   pdfMake.createPdf( doc ).getBase64( function( base64 ) {
      postMessage( { action: 'gen_pdf', base64: base64 } );
   } );
}

onmessage = function( evt ) {
   var action = evt.data.action, data = evt.data.data;
   switch ( action ) {
      case 'set': set( data ); break;
      case 'add': add( data ); break;
      case 'add_table'  : add_table( data ); break;
      case 'close_table': pop(); break;
      case 'gen_pdf': gen_pdf(); break;
   }
};

})();
//importScripts('tinyxmlw3cdom.js');
//var document=new DOMDocument(new dominimplementation());
var document={'createElements':函数(){return{};
var窗口=此;
importScripts('pdfmake.min.js','vfs_font.js');
(函数(){'use strict';
var文档,当前,上下文\u堆栈;
功能集(数据){
doc=数据;
如果(!doc.content)doc.content=[];
当前=文档内容;
上下文_堆栈=[当前];
}
集合({});
功能添加(数据){
当前推送(数据);
}
函数添加表(模板){
如果(!template)template={};
如果(!template.table)template={table:template};
如果(!template.table.body)template.table.body=[];
current.push(模板);//追加表
push(template.table.body);//将上下文切换到表体
}
功能推送(数据){
上下文栈推送(当前);
返回电流=数据;
}
函数pop(){

如果(context_stack.length看起来该工具需要DOM/文档,而workers没有。您可以为您浏览的节点使用虚拟DOM库,这可能很酷…非常感谢您的关注,先生..您是否有机会提示我一些从何处开始的链接..这对我真的很有帮助..再次感谢非常感谢您的帮助,先生@Sheepy..!您的代码非常有效..现在我正在调整它以适应我的布局..嗯,有没有马上发送docDefinition而不是手动数组?还有open函数(gen_pdf)在处理大型表格时不起作用,我认为这是浏览器的问题,因此如果改用下载功能会更好。非常感谢您的帮助,先生!这将解决我项目的未来问题。\n我尝试替换
open('data:application/pdf;base64,+evt.data.base64);
下载(“总账从:至.pdf”);
但它给了我一个“下载”未定义的错误。@melvnberd目前的浏览器没有一致的下载API,所以我建议使用第三方库。有一些,我用一个相对跨平台的库更新了答案的解释和代码。非常感谢@sheepy先生在这方面给我提供了真正的帮助。。我愿意我没有任何使用电脑的经验
importScripts( 'tinyxmlw3cdom.js' );
var window = this;
var document = new DOMDocument( new DOMImplementation() );
importScripts( 'pdfmake.min.js', 'vfs_fonts.js' );
<script src='FileSaver.min.js'></script>
<script>
function base64ToBlob( base64, type ) {
    var bytes = atob( base64 ), len = bytes.length;
    var buffer = new ArrayBuffer( len ), view = new Uint8Array( buffer );
    for ( var i=0 ; i < len ; i++ )
      view[i] = bytes.charCodeAt(i) & 0xff;
    return new Blob( [ buffer ], { type: type } );
}
//////////////////////////////////////////////////////////

var pdfworker = new Worker( 'worker.js' );

pdfworker.onmessage = function( evt ) {
   // open( 'data:application/pdf;base64,' + evt.data.base64 ); // Popup PDF
   saveAs( base64ToBlob( evt.data.base64, 'application/pdf' ), 'General Ledger.pdf' );
};

function pdf( action, data ) {
   pdfworker.postMessage( { action: action, data: data } );
}

pdf( 'add', 'Hello WebWorker' );
pdf( 'add_table', { headerRows: 1 } );
pdf( 'add', [ 'First', 'Second', 'Third', 'The last one' ] );
pdf( 'add', [ { text: 'Bold value', bold: true }, 'Val 2', 'Val 3', 'Val 4' ] );
pdf( 'close_table' );
pdf( 'add', { text: 'This paragraph will have a bigger font', fontSize: 15 } );
pdf( 'gen_pdf' ); // Triggers onmessage when it is done

// Alternative, one-size-fit-all usage
pdf( 'set', { pageOrientation: 'landscape', footer: { text: 'copyright 2015', fontSize: 8, alignment:'center'}, content:[ "header", { fontSize: 8, alignment: 'right', table: { headerRows: 1, body: [[1,2,3],[4,5,6]] } }] } );
pdf( 'gen_pdf' );

</script>
//importScripts( 'tinyxmlw3cdom.js' );
//var document = new DOMDocument( new DOMImplementation() );
var document = { 'createElementNS': function(){ return {} } };
var window = this;
importScripts( 'pdfmake.min.js', 'vfs_fonts.js' );

(function() { 'use strict';

var doc, current, context_stack;

function set ( data ) {
   doc = data;
   if ( ! doc.content ) doc.content = [];
   current = doc.content;
   context_stack = [ current ];
}
set( {} );

function add ( data ) {
   current.push( data );
}

function add_table ( template ) {
   if ( ! template ) template = {};
   if ( ! template.table ) template = { table: template };
   if ( ! template.table.body ) template.table.body = [];
   current.push( template ); // Append table
   push( template.table.body ); // Switch context to table body
}

function push ( data ) {
   context_stack.push( current );
   return current = data;
}

function pop () {
   if ( context_stack.length <= 1 ) return console.warn( "Cannot close pdf root" );
   context_stack.length -= 1;
   return current = context_stack[ context_stack.length-1 ];
}

function gen_pdf() {
   pdfMake.createPdf( doc ).getBase64( function( base64 ) {
      postMessage( { action: 'gen_pdf', base64: base64 } );
   } );
}

onmessage = function( evt ) {
   var action = evt.data.action, data = evt.data.data;
   switch ( action ) {
      case 'set': set( data ); break;
      case 'add': add( data ); break;
      case 'add_table'  : add_table( data ); break;
      case 'close_table': pop(); break;
      case 'gen_pdf': gen_pdf(); break;
   }
};

})();