2011-05-29 44 views
1

我正在处理数据。我通过setInterval设置了一个每5ms调用一次的工作函数。我正在计算函数运行所花费的时间,即0到1ms。我也计算函数实际调用的速度和大约80ms。javascript计时问题

我的问题是,如果它只需要1ms来运行函数,并且我每5ms调用一次,为什么每80ms调用一次?

我确实有第二个worker函数根据处理函数正在执行的当前数据更新画布,但是它在它自己的setInterval中运行。

这些数字是在Chrome中进行的。我已经在Opera,Safari,FF3和FF4中进行了测试,问题是一样的,尽管调用时间不同。 (所有这一切在Mac上)

我知道这个代码不是而是在IE中工作。我知道这部分是丑陋的..我还没有开始清理代码呢... 77到84行是setInterval调用。

您可以看到一个工作示例here

(function ($) { 
    var methods = { 
     init: function (options) { 
      return this.each(function() { 
       var $this = $(this); 
       $this.addClass('ansiScreen'); 
       var data = $this.data('ansi'); 
       if (!data) { 
        data = new Object(); 
        data.target = $this; 
        data.fontheight = 16; //12, 16, 22 
        data.fontwidth = Math.round(data.fontheight * 0.6) - 1; 
        data.canvas = $('<canvas width="' + (data.fontwidth * 80) + 'px" height="' + (data.fontheight * 25) + 'px">'); 
        $this.append(data.canvas); 
        data.ctx = data.canvas[0].getContext('2d'); 
        data.ctx.font = data.fontheight + 'px Courier New'; 
        data.processInterval = null; 
        data.screenInterval = null; 
        data.ansi = null; 
        data.ansiCode = null; 
        data.ansiPos = 0; 
        data.fgcolor = 'rgb(170, 170, 170)'; 
        data.bgcolor = 'rgb(0, 0, 0)'; 
        data.bold = false; 
        data.blink = false; 
        data.pos = [0, 0]; 
        data.savepos = [0, 0]; 
        data.screen = Array(); 
        data.last = 0; 
        for (var i = 0; i < 25; i++) { 
         data.screen.push(Array()); 
         for (var j = 0; j < 80; j++) { 
          data.screen[i].push([data.bgcolor, data.fgcolor, ' ']); 
         } 
        } 
        $this.data('ansi', data); 
       } 
      }); 
     }, 
     destroy: function() { 
      return this.each(function() { 
       var $this = $(this); 
       var data = $this.data('ansi'); 

       // Clean up 
       $(window).unbind('.ansi'); 
       data.tooltip.remove(); 
       $this.removeData('ansi'); 
      }); 
     }, 
     load: function (ansiUrl) { 
      return this.each(function() { 
       var $this = $(this); 
       var me = this; 
       $.ajax({ 
        'url': ansiUrl, 
        'data': 'text', 
        beforeSend: function (jqXHR, settings) { 
         jqXHR.overrideMimeType('text/plain; charset=x-user-defined'); 
        }, 
        success: function(ansiData) { 
         var data = $this.data('ansi'); 
         if (data.processInterval != null) { 
          clearInterval(data.processInterval); 
          clearInterval(data.screenInterval); 
         } 

         data.ansi = ansiData; 
         data.ansiPos = 0; 
         data.fgcolor = 'rgb(170, 170, 170)'; 
         data.bgcolor = 'rgb(0, 0, 0)'; 
         data.bold = false; 
         data.blink = false; 
         data.pos = [0, 0]; 
         data.savepos = [0, 0]; 

         var interval = setInterval(function() { 
          processAnsi.call(me); 
         }, 5); 
         data.processInterval = interval; 
         interval = setInterval(function() { 
          updateDisplay.call(me); 
         }, 30); 
         data.screenInterval = interval; 
         $this.data('ansi', data); 
         updateDisplay.call(me); 
        } 
       }); 
      }); 
     } 
    }; 

    $.fn.ansi = function (method) { 
     // Method calling logic 
     if (methods[method]) { 
      return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); 
     } else if (typeof method === 'object' || !method) { 
      return methods.init.apply(this, arguments); 
     } else { 
      $.error('Method ' + method + ' does not exist on jQuery.ansi'); 
     } 
    }; 

    // Process a byte from teh ansi data 
    function processAnsi() { 
     var start = new Date().getTime(); 
     var $this = $(this); 
     var data = $this.data('ansi'); 

     if (data.ansiPos > data.ansi.length) 
     { 
      clearInterval(data.processInterval); 
      clearInterval(data.screenInterval); 
      return; 
     } 

     var code = data.ansi.charCodeAt(data.ansiPos) & 0xff; 
     var char = data.ansi[data.ansiPos]; 
     data.ansiPos += 1; 
     var now = new Date().getTime(); 
     $this.data('ansi', data); 

     if (code < 33 || code > 126) 
     { 
      switch (code) 
      { 
       case 0: char = ''; break; 
       case 10: char = ''; cursorStartOfLine.call(this); break; 
       case 13: char = ''; cursorDown.call(this, 1); break; 
       case 27: char = ansiCode.call(this); break; 
       case 32: char = ' '; break; 
       case 176: char = '\u2591'; break; 
       case 177: char = '\u2592'; break; 
       case 178: char = '\u2593'; break; 
       case 179: char = '\u2502'; break; 
       case 185: char = '\u2563'; break; 
       case 186: char = '\u2551'; break; 
       case 187: char = '\u2557'; break; 
       case 188: char = '\u255D'; break; 
       case 191: char = '\u2510'; break; 
       case 192: char = '\u2514'; break; 
       case 193: char = '\u2534'; break; 
       case 194: char = '\u252C'; break; 
       case 195: char = '\u251C'; break; 
       case 196: char = '\u2500'; break; 
       case 197: char = '\u253C'; break; 
       case 180: char = '\u2524'; break; 
       case 200: char = '\u255A'; break; 
       case 201: char = '\u2554'; break; 
       case 204: char = '\u2560'; break; 
       case 205: char = '\u2550'; break; 
       case 215: char = '\u256B'; break; 
       case 217: char = '\u2518'; break; 
       case 218: char = '\u250C'; break; 
       case 219: char = '\u2588'; break; 
       case 220: char = '\u2584'; break; 
       case 221: char = '\u258C'; break; 
       case 222: char = '\u2590'; break; 
       case 223: char = '\u2580'; break; 
       case 250: char = '\u2022'; break; 
       case 254: char = '\u25a0'; break; 
       default: char = ''; var s = String.fromCharCode(code); break; 
      } 
     } 

     if (char === undefined) { 
      char = '[' + char + ']'; 
     } 
     if (char != '') { 
      putCharacter.call(this, char); 
     } 

     var end = new Date().getTime(); 
     $('#processTime').html('Requested Speed: 5ms, Process Speed: ' + (now-data.last) + 'ms, Process Time: ' + (end-start) + 'ms, Process Position: ' + data.ansiPos + ' of ' + data.ansi.length); 
     data = $this.data('ansi'); 
     data.last = now; 
     $this.data('ansi', data); 
    } 

    function ansiCode() { 
     var $this = $(this); 
     var data = $this.data('ansi'); 
     if (data.ansiPos > data.ansi.length) 
      return '-'; 

     var valid = /^[0-9;HABCDRsuJKmh]$/; 
     var end = /^[HABCDRsuJKmh]$/; 
     var char = data.ansi[data.ansiPos]; 
     var escape = ''; 
     if (char == '[') 
     { 
      var stop = false; 
      do { 
       data.ansiPos += 1; 
       var char = data.ansi[data.ansiPos]; 
       escape += char; 
       stop = end.test(char); 
      } while (valid.test(char) && !stop) 
      data.ansiPos += 1; 
     } 

     switch(escape[escape.length - 1]) 
     { 
      case 'J': 
       if (escape == '2J') { 
        clearDisplay.call(this); 
       } 
       break; 
      case 'A': 
       var lines = parseInt(escape.substring(0, escape.length - 1)); 
       if (isNaN(lines)) { lines = 1; } 
       data.pos[1] -= lines; 
       if (data.pos[1] < 0) { data.pos[1] = 0; } 
       break; 
      case 'B': 
       var lines = parseInt(escape.substring(0, escape.length - 1)); 
       if (isNaN(lines)) { lines = 1; } 
       cursorDown.call(this, lines); 
       break; 
      case 'C': 
       var spaces = parseInt(escape.substring(0, escape.length - 1)); 
       if (isNaN(spaces)) { spaces = 1; } 
       cursorForward.call(this, spaces); 
       break; 
      case 'D': 
       var lines = parseInt(escape.substring(0, escape.length - 1)); 
       if (isNaN(lines)) { lines = 1; } 
       data.pos[0] -= lines; 
       if (data.pos[0] < 0) { data.pos[0] = 0; } 
       break; 
      case 'H': 
       var codes = escape.substring(0, escape.length - 1).split(';'); 
       if (isNaN(codes[0])) { codes[0] = 1; } 
       if (isNaN(codes[1])) { codes[1] = 1; } 
       data.pos[0] = codes[1] - 1; 
       data.pos[1] = codes[0] - 1; 
       break; 
      case 's': 
       data.savepos[0] = data.pos[0]; 
       data.savepos[1] = data.pos[1]; 
       break; 
      case 'u': 
       data.pos[0] = data.savepos[0]; 
       data.pos[1] = data.savepos[1]; 
       break; 
      case 'm': 
       var codes = escape.substring(0, escape.length - 1).split(';'); 
       for (var i=0; i < codes.length; i++) { 
        var code = codes[i]; 
        switch (code) { 
         case '0': 
          data.bold = false; 
          data.blink = false; 
          data.fgcolor = 'rgb(170, 170, 170)'; 
          data.bgcolor = 'rgb(0, 0, 0)'; 
          break; 
         case '1': 
          data.bold = true; 
          break; 
         case '5': 
          data.blink = true; 
          break; 
         case '30': 
          data.fgcolor = !data.bold ? 'rgb(0, 0, 0)' : 'rgb(85, 85, 85)'; 
          break; 
         case '31': 
          data.fgcolor = !data.bold ? 'rgb(170, 0, 0)' : 'rgb(255, 85, 85)'; 
          break; 
         case '32': 
          data.fgcolor = !data.bold ? 'rgb(0, 170, 0)' : 'rgb(85, 255, 85)'; 
          break; 
         case '33': 
          data.fgcolor = !data.bold ? 'rgb(170, 85, 0)' : 'rgb(255, 255, 0)'; 
          break; 
         case '34': 
          data.fgcolor = !data.bold ? 'rgb(0, 0, 170)' : 'rgb(85, 85, 255)'; 
          break; 
         case '35': 
          data.fgcolor = !data.bold ? 'rgb(170, 0, 170)' : 'rgb(255, 85, 255)'; 
          break; 
         case '36': 
          data.fgcolor = !data.bold ? 'rgb(0, 170, 170)' : 'rgb(85, 255, 255)'; 
          break; 
         case '37': 
          data.fgcolor = !data.bold ? 'rgb(170, 170, 170)' : 'rgb(255, 255, 255)'; 
          break; 
         case '40': 
          data.bgcolor = !data.bold ? 'rgb(0, 0, 0)' : 'rgb(85, 85, 85)'; 
          break; 
         case '41': 
          data.bgcolor = !data.bold ? 'rgb(170, 0, 0)' : 'rgb(255, 85, 85)'; 
          break; 
         case '42': 
          data.bgcolor = !data.bold ? 'rgb(0, 170, 0)' : 'rgb(85, 255, 85)'; 
          break; 
         case '43': 
          data.bgcolor = !data.bold ? 'rgb(170, 85, 0)' : 'rgb(255, 255, 0)'; 
          break; 
         case '44': 
          data.bgcolor = !data.bold ? 'rgb(0, 0, 170)' : 'rgb(85, 85, 255)'; 
          break; 
         case '45': 
          data.bgcolor = !data.bold ? 'rgb(170, 0, 170)' : 'rgb(255, 85, 255)'; 
          break; 
         case '46': 
          data.bgcolor = !data.bold ? 'rgb(0, 170, 170)' : 'rgb(85, 255, 255)'; 
          break; 
         case '47': 
          data.bgcolor = !data.bold ? 'rgb(170, 170, 170)' : 'rgb(255, 255, 255)'; 
          break; 
         default: 
          $('#debug').html($('#debug').html() + '<br>Unknown Attribute: ' + code); 
          break; 
        } 
       } 
       break; 
      default: 
       $('#debug').html($('#debug').html() + '<br>' + escape); 
       break; 
     } 

     $this.data('ansi', data); 
     return ''; 
    } 


    // Move the cursor position up a number of lines 
    function cursorStartOfLine(lines) { 
     var $this = $(this); 
     var data = $this.data('ansi'); 
     data.pos[0] = 0; 
     $this.data('ansi', data); 
    } 

    // Move the cursor position up a number of lines 
    function cursorDown(lines) { 
     var $this = $(this); 
     var data = $this.data('ansi'); 
     data.pos[1] += lines; 
     if (data.pos[1] > data.screen.length - 1) { 
      data.pos[1] = data.screen.length - 1; 

      for (var i = 0, length1 = data.screen.length - 1; i < length1; ++i) { 
       var a = data.screen[i]; // cache object 
       var b = data.screen[i+1]; // cache object 
       for (var j = 0, length2 = a.length; j < length2; ++j) { 
        a[j] = b[j]; 
       } 
      } 

      for (var j = 0, length2 = a.length; j < length2; ++j) { 
       data.screen[data.screen.length-1][j] = ['#000000', '#ffffff', ' ']; 
      } 

     } 
     $this.data('ansi', data); 
    } 

    // Move the cursor position back a number of columns 
    function cursorBack(cols) { 
     var $this = $(this); 
     var data = $this.data('ansi'); 
     data.pos[0] -= cols; 
     if (data.pos[0] < 0) { data.pos[0] = 0; } 
     $this.data('ansi', data); 
    } 

    // Move the cursor position forward a number of columns 
    function cursorForward(cols) { 
     var $this = $(this); 
     var data = $this.data('ansi'); 
     data.pos[0] += cols; 
     if (data.pos[0] > data.screen[0].length - 1) { 
       //data.pos[0] = data.screen[0].length - 1; 
       data.pos[0] = 0; 
       cursorDown.call(this,1); 
     } 
     $this.data('ansi', data); 
    } 

    // Puts a character on screen 
    function putCharacter(character) { 
     var $this = $(this); 
     var data = $this.data('ansi'); 
     var style = 'background-color:' + data.bgcolor+';'; 
     style += 'color:' + data.fgcolor+';'; 
     data.screen[data.pos[1]][data.pos[0]] = [data.bgcolor, data.fgcolor, character, data.blink]; 
     $this.data('ansi', data); 

     // Move forward 1 character 
     cursorForward.call(this, 1); 
    } 

    // Clear the screen 
    function clearDisplay() { 
     var $this = $(this); 
     var data = $this.data('ansi'); 
     for (var i = 0; i < data.screen.length; i++) { 
      for (var j = 0; j < data.screen[i].length; j++) { 
       data.screen[i][j] = [data.bgcolor, data.fgcolor, ' ', data.blink]; 
      } 
     } 
     data.pos = [0, 0]; 
     $this.data('ansi', data); 
    } 

    // Update the container with the current screen 
    function updateDisplay() { 
     var start = new Date().getTime(); 
     var $this = $(this); 
     var data = $this.data('ansi'); 

     for (var i = 0, length1 = data.screen.length; i < length1; ++i) { 
      var a = data.screen[i]; // cache object 
      for (var j = 0, length2 = a.length; j < length2; ++j) { 
       data.ctx.fillStyle = a[j][0]; 
       data.ctx.fillRect (data.fontwidth * j, data.fontheight * i, data.fontwidth, data.fontheight); 
       data.ctx.fillStyle = a[j][1]; 
       data.ctx.textBaseline = "top"; 
       data.ctx.fillText(a[j][2], data.fontwidth * j, data.fontheight * i); 
      } 
     } 

     var end = new Date().getTime(); 
     $('#frameTime').html('Frame Draw Time: ' + (end-start)); 
    } 
})(jQuery); 

回答

1

还要记住不同的浏览器有不同的最小间隔。将间隔设置为5ms可能会触发一些浏览器进行最小间隔检查。 此外,您运行的定时器越多,浏览器将返回到队列的起始位置所用的时间越长

+0

谢谢,我没有意识到间隔已排队,而不是线程化。我必须加快我的显示更新代码。 – Justin808 2011-05-29 17:00:46

0

Javascript是单线程的,所以你用setInterval调用的第二个函数会延迟第一个。