[英]javascript stop an infinite loop
這是 node.js。
我有一個 function,如果滿足幾個條件,它可能會變成無限循環。 不受信任的用戶設置了這些條件,因此為了這個問題的目的,請假設無限循環是無法修復的。
我仍然需要一種方法來停止無限循環。
這是我正在嘗試做的一些示例代碼:
var infiniteloop = false;
var condition = true
function loop () {
while (condition) {
console.log('hi')
if (infiniteloop) {
condition = false
console.log('oh last one')
}
}
}
loop()
所以有幾個問題基於我正在嘗試做的事情。
infiniteloop
變量設置為 true,循環就會停止,對嗎?infiniteloop
循環變量在同一進程中,則它在循環時不能更改。 我必須將變量存儲在不同的進程中嗎?謝謝你的幫助。
基於其他建議的解決方案:
function Worker()
{
this.MaxIterations = 1000000;
this.Enabled = true;
this.condition = true;
this.iteration = 0;
this.Loop = function()
{
if (this.condition
&& this.Enabled
&& this.iteration++ < this.MaxIterations)
{
console.log(this.iteration);
setTimeout(this.Loop.bind(this),0);
}
};
this.Stop = function()
{
this.Enabled = false;
};
}
var w = new Worker();
setTimeout(w.Loop.bind(w), 0);
setTimeout(w.Stop.bind(w), 3000);
不確定這是否是最佳選擇,但是應該能按預期工作。
使用setTimeout恢復循環允許主node.js事件循環處理其他事件,例如w.Stop。
在這種情況下,無窮大取決於循環的最大迭代次數。 此代碼阻止了JavaScript的單線程性質,因此,除非使用Web Worker,否則您將始終鎖定所有內容。 最好不要每隔x秒檢查一次,因為此代碼無論如何都會阻止執行間隔或超時,而是將其作為循環迭代的最大閾值放入循環本身。
var infiniteloop = false;
var condition = true;
var loopCounter = 1;
var maxLoopIterations = 1000;
function loop () {
while (condition) {
console.log('hi');
infiniteLoop = (loopCounter >= maxLoopIterations);
if (infiniteloop) {
condition = false;
console.log('oh last one');
break;
}
loopCounter++;
}
}
實際上,您不需要停止無限循環。 使用setImmediate
例如:
var immediateId;
function loop () {
console.log('hi');
immediateId = setImmediate(loop);
}
loop();
這段代碼將一直打個招呼 ,直到您停止它。
//stop the loop:
clearImmediate(immediateId);
為什么使用setImmediate
RangeError: Maximum call stack size exceeded
; 更進一步,
我創建此模塊是為了輕松管理無限循環:
var util = require('util');
var ee = require('events').EventEmitter;
var Forever = function() {
ee.call(this);
this.args = [];
};
util.inherits(Forever, ee);
module.exports = Forever;
Forever.prototype.add = function() {
if ('function' === typeof arguments[0]) {
this.handler = arguments[0];
var args = Array.prototype.slice.call(arguments, 1);
if (args.length > 0) {
this.args = args;
}
} else {
this.emit('error', new Error('when using add function, the first argument should be a function'));
return 0;
}
return this;
};
Forever.prototype.run = function() {
var handler = this.handler;
var args = this.args;
var that = this;
this._immediateId = setImmediate(function() {
if (typeof handler === 'function') {
switch (args.length) {
// fast cases
case 0:
handler.call(that);
that.run();
break;
case 1:
handler.call(that, args[0]);
that.run();
break;
case 2:
handler.call(that, args[0], args[1]);
that.run();
break;
// slower
default:
handler.apply(that, args);
that.run();
}
} else {
//no function added
that.emit('error', new Error('no function has been added to Forever'));
}
});
};
Forever.prototype.stop = function() {
if (this._immediateId !== null) {
clearImmediate(this._immediateId);
} else {
this.emit('error', new Error('You cannot stop a loop before it has been started'));
}
};
Forever.prototype.onError = function(errHandler) {
if ('function' === typeof errHandler) {
this.on('error', errHandler);
} else {
this.emit('error', new Error('You should use a function to handle the error'));
}
return this;
};
用法示例:
var Forever = require('path/to/this/file');
var f = new Forever();
// function to be runned
function say(content1, content2){
console.log(content1 + content2);
}
//add function to the loop
//the first argument is the function, the rest are its arguments
//chainable api
f.add(say, 'hello', ' world!').run();
//stop it after 5s
setTimeout(function(){
f.stop();
}, 5000);
而已。
您可以創建一個子進程(分支)以檢查您的實際進程是否正在響應。 如果沒有響應,則分叉將向父級發送消息-殺死父級和分叉。 您在本要點中可以看到的與此類似的東西: https : //gist.github.com/kevinohara80/3173692
我想提出我的解決方案。 就我而言,我有幾個無限循環( while(true)
),這些無限循環僅由break
語句終止。 很難確定是否滿足這些break
語句的條件,而且該算法不是我自己開發的,因此也不可以選擇完全重構。
我喜歡@JasonSebring帶有循環計數器的簡單解決方案。 在我的情況下,只需為迭代次數設置一個限制就可以了。 但是我不想將所有這些變量都插入到我的代碼中,此外,我還需要一個適用於嵌套循環的解決方案。 所以我想出了這個包裝函數:
/**
* Stop potential infinite loops after a certain number of iterations.
* @param loopLimit - The maximum number of iterations before loop is aborted.
* @param silentStop - Whether to abort the loop silently or throw an error instead.
* @param callBack - Function representing the inner code of the loop.
*/
static finiteLoopHelper(loopLimit, silentStop, callBack) {
let loopCounter = 0;
let stopLoop = false;
while (!stopLoop) {
// Return value from the callback can invoke an early stop, like a break statement.
stopLoop = callBack();
loopCounter++;
if (loopCounter >= loopLimit) {
stopLoop = true;
if (!silentStop) {
throw Error(`Loop aborted after ${loopLimit} iterations.`);
}
}
}
}
用法是這樣的:
let someVariable = 0;
finiteLoopHelper(1000, false, () => { // this line replaces "while (true) {"
someVariable = someCalculation();
if (someVariable === someCondition) {
return false; // like continue in a normal loop.
}
codeNotExecutedInCaseOfContinue();
if (someVariable === someOtherCondition) {
return true; // like break in a normal loop.
}
// Return value at the end can be omitted, because without it the function
// will return undefined which also keeps the loop running.
// return false;
});
如果循環之前有條件,則必須在arrow函數中檢查此條件,並使用return true;
就像上面的例子一樣。
由於不公開循環計數器,因此可以嵌套此解決方案,而無需為內部循環的計數器找到不同的變量名。
在 function 中,只需返回 false 或 undefined。
在 function 中手動拋出 new Error("ERROR")。
將 function 設置為在計時器上運行 - var timer = setInterval(FUNCTION, 1000)。 然后清除它停止 - clearInterval(timer)
使用可以終止的工作人員運行腳本。
使用 window.stop() 來阻止頁面加載和運行。
僅適用於 NodeJS – 使用 process.abort() 或 process.exit()。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.