在一个可填充的'线程'中运行JS;检测和取消长时间运行的进程 [英] Running JS in a killable 'thread'; detecting and canceling long-running processes

查看:98
本文介绍了在一个可填充的'线程'中运行JS;检测和取消长时间运行的进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Summary: How can I execute a JavaScript function, but then "execute" (kill) it if it does not finish with a timeframe (e.g. 2 seconds)?

我正在为以交互方式编写和测试PEG语法。不幸的是,我用于使用PEG解析的JavaScript库有'bug'某些写得不好或未完成的语法导致无限执行(甚至某些浏览器都没有检测到)。当你突然浏览器锁定并且你失去了所有的辛苦工作时,你可以愉快地打字,处理你的语法。

I'm writing a web application for interactively writing and testing PEG grammars. Unfortunately, the JavaScript library I'm using for parsing using a PEG has a 'bug' where certain poorly-written or unfinished grammars cause infinite execution (not even detected by some browsers). You can be happily typing along, working on your grammar, when suddenly the browser locks up and you lose all your hard work.

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

Right now my code is (very simplified):

grammarTextarea.onchange = generateParserAndThenParseInputAndThenUpdateThePage;

我想将其更改为:

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

我考虑使用iframe或其他标签/窗口来执行内容,但即使这样凌乱解决方案不保证能够在最新版本中使用主要浏览器。但是,我很高兴接受仅适用于最新版Safari,Chrome和Firefox的解决方案。

I've considered using an iframe or other tab/window to execute the content, but even this messy solution is not guaranteed to work in the latest versions of major browsers. However, I'm happy to accept a solution that works only in latest versions of Safari, Chrome, and Firefox.

推荐答案

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

Web workers provide this capability—as long as the long-running function does not require access to the window or document or closures—albeit in a somewhat-cumbersome manner. Here's the solution I ended up with:

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);

这篇关于在一个可填充的'线程'中运行JS;检测和取消长时间运行的进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆