我在客户端(Cordova应用程序)使用pdfmake生成PDF文件。
文档定义越复杂, pdfmake 生成文档所需的时间越长。
因此,我的目的是严格限制 pdfmake 生成文档所需的时间,类似于timeout命令在bash中执行的操作,并指示用户是否它未能完成。
这是我尝试做的事情的片段:
runFor(10, function(){ // run this function for a maximum of 10s
pdfMake.createPdf(documentDefinition).getBase64(function(b64buff){
//do something with the result
});
}, ontimeout);
答案 0 :(得分:0)
一种可能性是在JavaScript中,即setInterval函数。
var i =0;
setInterval(function(){i++;console.log(i)},1000);
此片段每秒增加1。现在在你想要执行的函数中,检查i以查看它是否足够大以将代码转移到中断。只需确保在重新启动功能时重置i。
答案 1 :(得分:0)
理想情况下,您需要更改功能。也许它可能需要一个条件作为参数。
取决于它所做的事情,永远'你可以生成一个运行该函数的子进程,然后在一段时间后终止该进程。
答案 2 :(得分:0)
对不起,这个解决方案并不像你或未来读者想要的那样通用,但它确实有用,而且我还无法提出更好的想法......
WebWorker interface作为terminate
方法,一旦主线程调用,就会立即停止工作人员的执行。
我们可以使用它在主线程上启动一个定时器,当达到超时阈值时,该定时器将调用此Worker.terminate
方法。
这不是通用的,因为它意味着您的代码必须能够在Worker中运行 但你很幸运,因为它似乎 pdfmake 库。
所以你可以这样写:
<强> pdfmakeWorkerScript.js 强>
// first import needed assets
self.importScripts('pdfmake.min.js');
self.importScripts('vfs_fonts.js');
self.onmessage = function(e) {
if(e.data.docDefinition){
pdfMake.createPdf(e.data.docDefinition).getBase64(function(b64) {
self.postMessage(b64);
});
}
};
主页 中的
function generatePDFinLessThan(docDefinition, maxTimeInSec, onsuccess, ontimeout){
var worker = new Worker('pdfmakeWorkerScript.js');
var timer = setTimeout(stopWorker, maxTimeInSec * 1000);
worker.onmessage = function(e) {
clearTimeout(timer);
if(typeof onsuccess === 'function')
onsuccess(e.data);
}
function stopWorker() {
worker.terminate();
if(typeof ontimeout === 'function')
ontimeout();
}
worker.postMessage({docDefinition: docDefinition});
}
// usage
var docDefinition = {...};
generatePDFinLessThan(docDefinition, 10, function onsuccess(data) {...}, function ontimeout() {...});
一个修改后的版本,以便它可以在StackSnippets中运行:
const workerURL = generateWorkerURL(); // should normally just be a string url pointing to your worker's .js
const docDefinition = {
content: 'This is an sample PDF printed with pdfMake'
};
function generatePDFinLessThan(max_duration, onsuccess, ontimeout) {
let timer = null;
const worker = new Worker(workerURL);
worker.onmessage = e => {
if (e.data === "assets ready") { // for slow connections
startTimer();
return;
}
if (e.data.type === "success"){
clearTimeout(timer);
if(typeof onsuccess === 'function') {
onsuccess(e.data.data);
}
}
};
worker.postMessage({
docDefinition: docDefinition,
// demo only!
waitingTime: waitingInput.value * 1000
// end demo only
});
function startTimer() {
console.log('assets ready'); // rawgit is really long for me...
timer = setTimeout(() => {
worker.terminate();
if (typeof ontimeout === 'function') {
ontimeout();
}
}, max_duration * 1000);
}
}
btn.onclick = e => generatePDFinLessThan(+maxTimeInput.value, onsuccess, ontimeout);
function onsuccess(data) {
console.log(data);
}
function ontimeout() {
console.error('operation timed out');
}
// demo only!
function generateWorkerURL() {
const script = document.querySelector('script[type="worker-script"]');
const blob = new Blob([script.textContent], {
type: 'application/javascript'
});
return URL.createObjectURL(blob);
}
&#13;
<script type="worker-script">
/* pdfmake generation in a worker */
const pdfmake_baseURI = "https://cdn.rawgit.com/bpampuch/pdfmake/master/build/";
// first import needed assets
self.importScripts(pdfmake_baseURI + 'pdfmake.min.js');
self.importScripts(pdfmake_baseURI + 'vfs_fonts.js');
self.postMessage('assets ready');
onmessage = e => {
if(e.data.docDefinition){
// for demo only!
wait(e.data.waitingTime);
// end for demo only
pdfMake.createPdf(e.data.docDefinition).getBase64(b64 => {
self.postMessage({type: 'success', data: b64});
});
}
};
// for demo only!
function wait(dur) {
const now = performance.now();
while(performance.now() - now < dur){}
}
</script>
<button id="btn">generate pdf</button><br>
<label>Maximum execution time (in sec) <input type="number" id="maxTimeInput" value="5"></label><br>
<label>Waiting time in worker (in sec) <input type="number" id="waitingInput" value="0"></label>
&#13;
答案 3 :(得分:0)
如何在Promise.all中使用两个诺言?
一个诺言将触发一个函数,该函数将:1)启动计时器以拒绝,这将结束Promise.all; 2)一个函数,如果目标函数完成,它将每50毫秒检查一次布尔值
第二个承诺将触发目标函数,并在完成后将布尔值设置为true
目标函数应该是异步函数
async function runFor(maxTimeMS, funcAsync) {
let completed = false;
try {
await Promise.all([
new Promise((resolve, reject) => {
setInterval(() => {
if (completed) {
resolve();
}
}, 50); // check if completed every 50ms
setTimeout(reject, maxTimeMS); // timeMS is max time to wait for func
}),
new Promise( async () => await funcAsync() )
.then(() => { completed = true; })
]);
} catch (e) {
// if funcAsync does not complete, you will get an exception here
}
}