javascript计时问题

时间:2011-05-29 09:58:51

标签: javascript jquery setinterval

我正致力于处理数据。我设置了一个按setInterval每隔5ms调用一次的工作函数。我正在计算函数运行所需的时间,为0到1毫秒。我也在计算实际调用函数的速度和大约80ms。

我的问题是,如果只需要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);

2 个答案:

答案 0 :(得分:1)

还要记住,不同的浏览器有不同的最小间隔。将间隔设置为5ms可能会触发某些浏览器的最小间隔检查。 此外,运行的计时器越多,浏览器返回队列开始的时间就越长

答案 1 :(得分:0)

Javascript是单线程的,因此使用setInterval调用的第二个函数会延迟第一个函数。