Установить максимальное время выполнения для функции

1

Я создаю PDF файлы, используя pdfmake на стороне клиента (приложение cordova).

Чем сложнее определение документа, тем длиннее значение pdfmake для создания документа.

Таким образом, мое намерение состоит в том, чтобы ограничить время, необходимое для создания документа pdfmake, что-то вроде команды тайм-аута в 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
    Пожалуйста, покажите свою функцию, это цикл, рекурсивный, AJAX?
Показать ещё 10 комментариев
Теги:
cordova
pdfmake

3 ответа

0

Я сожалею, что это решение не такое общее, как вы или будущие читатели, возможно, захотите, но это действительно работает, и я не могу прийти с лучшей идеей...

Интерфейс WebWorker как метод terminate, который немедленно остановит выполнение Рабочего момента, вызванного основным потоком.
Мы можем использовать это, чтобы запустить таймер в основном потоке, который вызовет этот метод Worker.terminate когда достигнут порог тайм-аута.

Это не является общим, потому что это означает, что ваш код должен работать внутри Рабочего.
Но вам повезло, так как кажется, что библиотека 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 .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);
}
<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>
0

В идеале вам нужно изменить функцию. Возможно, это может быть условие как параметр.

В зависимости от того, что он делает, что принимает "навсегда", вы можете создать дочерний процесс, который запускает функцию, а затем убить процесс через определенное время.

0

Одна возможность в JavaScript - функция setInterval.

var i =0;
setInterval(function(){i++;console.log(i)},1000);

Этот снипп увеличивает я на 1 каждую секунду. Теперь в функции, которую вы хотите выполнить, сделайте проверку на i, чтобы узнать, достаточно ли она, чтобы перевести код на прерывание. Просто убедитесь, что вы сбросили я при перезапуске функции.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню