2012-07-13 219 views
4

這是node.js.javascript停止無限循環

我有一個函數可能會成爲一個無限循環,如果滿足幾個條件。不可信用戶爲了這個問題設置了這些條件,請假設無限循環是不可修復的。

我仍然需要一種方法來阻止無限循環。

這裏是我想要做的一些示例代碼:

var infiniteloop = false; 
var condition = true 
function loop() { 
    while (condition) { 
    console.log('hi') 
    if (infiniteloop) { 
     condition = false 
     console.log('oh last one') 
    } 
    } 
} 

loop() 

依據是什麼,我試圖這樣做的一些問題。

  1. 如果將infiniteloop變量設置爲true,循環將停止正確嗎?
  2. 如何檢測無限循環?每3秒檢查一次會很好。
  3. 如果infiniteloop變量位於同一進程中,則該變量在循環時不能更改。我必須將變量存儲在不同的進程中?
  4. 無論檢測到無限循環需要生活在不同的過程?理想情況下,同樣的過程會很好,但無論什麼作品?

感謝您的幫助。

+0

爲什麼不只是在迭代次數上設置一個上限呢? – jbabey 2012-07-13 18:45:12

回答

2

基礎上的其他提案的混合溶液:

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。

+0

這不完全是我用過的,但是這裏的一堆答案讓我有了一個解決方案。謝謝。 – Harry 2012-07-14 03:59:52

+0

你能編輯你的文章來添加你的最終解決方案嗎? – 2012-07-14 18:41:28

1

無窮大在這種情況下取​​決於循環的最大迭代次數。此代碼阻止了JavaScript的單線程特性,因此除非您使用Web工作人員,否則您將鎖定所有內容。最好不要每隔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++; 
    } 
} 
+0

循環是無限的。我無法設置最大迭代。 – Harry 2012-07-13 18:35:28

+0

你必須有一種阻止循環執行的方式,比如讓setInterval產生它內部的工作,否則它會一直阻塞。你應該把實際的例子。如果它有一個網絡電話或類似的東西,將完美地做你正在問的東西。 – 2012-07-13 18:36:44

+0

是的,關於網絡通話是正確的。這是serverside javascript,所以我假設我可以調用一個不同的進程來返回'infiniteloop' var。這就是我問的問題3 – Harry 2012-07-13 18:40:13

1

其實,你不需要停止無限循環。使用setImmediate

例如:

var immediateId; 

function loop() { 
    console.log('hi'); 
    immediateId = setImmediate(loop); 
} 

loop(); 

這個代碼塊會一直說,直到你停止它。

//stop the loop: 
clearImmediate(immediateId); 

爲什麼使用setImmediate

  1. 內存罪耗保持在較低水平,不會引起存儲器韭菜;
  2. 不會拋出RangeError: Maximum call stack size exceeded;
  3. 表現很好;

更進一步,

我創造了這個模塊可以輕鬆管理數量無限循環:

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

就是這樣。