在一个可用的“线程”中运行JS;检测和取消长时间运行的进程

时间:2014-02-22 15:15:37

标签: javascript html5 multithreading web-worker

摘要:我如何执行JavaScript函数,但如果它没有按时间帧(例如2秒)完成,那么“执行”(杀死)它?

详细信息

我正在为interactively writing and testing PEG grammars编写一个Web应用程序。不幸的是,我用于使用PEG进行解析的JavaScript库具有a 'bug',其中某些写得不好或未完成的语法会导致无限执行(甚至某些浏览器都检测不到)。当浏览器突然锁定并且你失去了所有的辛勤工作时,你可以愉快地打字,研究你的语法。

现在我的代码是(非常简化):

grammarTextarea.onchange = generateParserAndThenParseInputAndThenUpdateThePage;

我想将其更改为:

grammarTextarea.onchange = function(){
  var result = runTimeLimited( generateParserAndThenParseInput, 2000 );
  if (result) updateThePage();
};

我考虑使用iframe或其他标签/窗口来执行内容,但即使是这个混乱的解决方案is not guaranteed to work in the latest versions of major browsers也是如此。但是,我很高兴接受仅适用于最新版Safari,Chrome和Firefox的解决方案。

1 个答案:

答案 0 :(得分:2)

Web工作者提供此功能 - 只要长时间运行的功能不需要访问窗口或文档或闭包 - 尽管以某种麻烦的方式。这是我最终得到的解决方案:

<强> main.js

var worker, activeMsgs, userTypingTimeout, deathRowTimer;
killWorker(); // Also creates the first one

grammarTextarea.onchange = grammarTextarea.oninput = function(){
  // Wait until the user has not typed for 500ms before parsing
  clearTimeout(userTypingTimeout);
  userTypingTimeout = setTimeout(askWorkerToParse,500);
}

function askWorkerToParse(){
  worker.postMessage({action:'parseInput',input:grammarTextarea.value});
  activeMsgs++;                                // Another message is in flight
  clearTimeout(deathRowTimer);                 // Restart the timer
  deathRowTimer = setTimeout(killWorker,2000); // It must finish quickly
};

function killWorker(){
  if (worker) worker.terminate();   // This kills the thread
  worker = new Worker('worker.js')  // Create a new worker thread
  activeMsgs = 0;                   // No messages are pending on this new one
  worker.addEventListener('message',handleWorkerResponse,false);
}

function handleWorkerResponse(evt){
  // If this is the last message, it responded in time: it gets to live.
  if (--activeMsgs==0) clearTimeout(deathRowTimer);
  // **Process the evt.data.results from the worker**
},false);

<强> worker.js

importScripts('utils.js') // Each worker is a blank slate; must load libs

self.addEventListener('message',function(evt){
  var data = evt.data;
  switch(data.action){
    case 'parseInput':
      // Actually do the work (which sometimes goes bad and locks up)
      var parseResults = parse(data.input);

      // Send the results back to the main thread.
      self.postMessage({kind:'parse-results',results:parseResults});
    break;
  }
},false);