摘要:我如何执行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的解决方案。
答案 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);