在函数上设置最大执行时间

时间:2017-12-05 03:56:49

标签: javascript cordova pdfmake

我在客户端(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);

4 个答案:

答案 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中运行:

&#13;
&#13;
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;
&#13;
&#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
  }
}