简体   繁体   中英

how to get the good performance in the big dom with jquery?

I wrote a little program in Javascript with jquery.

   var mlife = function (i, j, alive) {
    var face = '<div class="life" id="l_' + i + '_' + j + '"/>';
    var f = $(face);
    var ps = new Array();
    //var interval;
    this.draw=function() {
        if (alive) {
            f.addClass('l');
        } else {
            f.removeClass('l');
        }
    };
    this.aliveCheck=function() {
        var alivecount = 0;
        for (var i = 0; i < ps.length; i++) {
            var el = $('#l_' + ps[i]);
            if (el.length > 0) {
                if (el.hasClass('l')) {
                    alivecount++;
                }
            }
        }
        if (alive) {
            if (alivecount < 2) {
                alive = false;
            } else if (alivecount == 2 || alivecount == 3) {
                alive = alive;
            } else if (alivecount > 3) {
                alive = false;
            }
        } else {
            if (alivecount == 3) {
                alive = true;
            }
        }
        //_draw();
    };
    this.getface = function () {
        return f;
    };
    function _init() {
        ps.push((i - 1) + '_' + (j - 1));
        ps.push((i - 1) + '_' + (j + 1));
        ps.push((i + 1) + '_' + (j - 1));
        ps.push((i + 1) + '_' + (j + 1));
        ps.push(i + '_' + (j - 1));
        ps.push(i + '_' + (j + 1));
        ps.push((i + 1) + '_' + j);
        ps.push((i - 1) + '_' + j);
        if (alive) {
            f.addClass('l'); 
        }

    };
    _init();
}
$(function () { 
    var html = "";
    var alive = false;
    var cells = new Array();

    for (var i = 0; i < 100; i++) {
        for (var j = 0; j < 100; j++) {
            if (Math.random() > 0.90) {
                alive = true;
            } else {
                alive = false;
            }
            var l = new mlife(i, j, alive);

            cells.push(l);
            $('#show').append(l.getface()); 
        }
    }

    setInterval(allAliveCheck,1000);


    function allAliveCheck(){

        for(var i=0;i<cells.length;i++){
            cells[i].aliveCheck();
        }
        for(var i=0;i<cells.length;i++){
            cells[i].draw();
        }

    }







});

http://jsfiddle.net/chanjianyi/upgvzm78/1/

it's about the "game of life": http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life

but I found it's very bad performance that control a lot of div.

So anybody have ideas to optimize my program?

jQuery is slow. Ditch jQuery and it runs much faster. Here's an example.

 var mlife = function(i, j, alive) { // var face = '<div class="life" id="l_' + i + '_' + j + '"/>'; var f = document.createElement('div'); f.className = 'life'; f.id = 'l_' + i + '_' + j; var ps = []; //var interval; this.draw = function() { if (alive) { f.classList.add('l'); } else { f.classList.remove('l'); } }; this.aliveCheck = function() { var alivecount = 0; for (var i = 0; i < ps.length; i++) { var el = document.getElementById('l_' + ps[i]); if (el) { if (el.classList.contains('l')) { alivecount++; } } } if (alive) { if (alivecount < 2) { alive = false; } else if (alivecount == 2 || alivecount == 3) { alive = alive; } else if (alivecount > 3) { alive = false; } } else { if (alivecount == 3) { alive = true; } } //_draw(); }; this.getface = function() { return f; }; function _init() { ps.push((i - 1) + '_' + (j - 1)); ps.push((i - 1) + '_' + (j + 1)); ps.push((i + 1) + '_' + (j - 1)); ps.push((i + 1) + '_' + (j + 1)); ps.push(i + '_' + (j - 1)); ps.push(i + '_' + (j + 1)); ps.push((i + 1) + '_' + j); ps.push((i - 1) + '_' + j); if (alive) { f.classList.add('l'); } }; _init(); } var html = ""; var alive = false; var cells = []; for (var i = 0; i < 100; i++) { for (var j = 0; j < 100; j++) { if (Math.random() > 0.90) { alive = true; } else { alive = false; } var l = new mlife(i, j, alive); cells.push(l); document.getElementById('show').appendChild(l.getface()); } } setInterval(allAliveCheck, 1000); function allAliveCheck() { for (var i = 0; i < cells.length; i++) { cells[i].aliveCheck(); } for (var i = 0; i < cells.length; i++) { cells[i].draw(); } } 
 #show { width: 500px; height: 500px; border: 0px solid red; } .life { width: 5px; height: 5px; background: black; float: left; } .l { background: blue; } 
 <body> <div id="show"></div> </body> 

Consider storing the playfield data as a simple array, rather than storing it in HTML elements. This way you can make arbitrary frontends to display the same data. A canvas or a simple preformatted block of text could give the same results visually; either one might perform better than a bunch of divs.

I'd suggest posting your code on codereview.stackexchange.com. There is a lot of room for improvement in this code; CR is a good venue for learning how to improve it.

Here's an example of how a simple CA might look (this is something I was working on for fun a few weeks ago). It uses a bunch of button elements to display the grid, but notice how the display routine could easily be swapped out with a canvas or some other mechanism.

 // // Cell // function Cell(grid, x, y) { /** @type Grid */ this.grid = grid; /** @type number */ this.x = x; /** @type number */ this.y = y; } Cell.prototype.getAdjacent = function() { var cellX = this.x, cellY = this.y, grid = this.grid, result = [], cell; for (var y = cellY - 1; y <= cellY + 1; y++) { for (var x = cellX - 1; x <= cellX + 1; x++) { if (x == cellX && y == cellY) { continue; } cell = grid.getCell(x, y); cell && result.push(cell); } } return result; }; // // Grid // function Grid(width, height) { /** @type number */ this.width = width; /** @type number */ this.height = height; /** @type Array.<Cell> */ this.cells = []; this.initCells(); } Grid.prototype.initCells = function() { var width = this.width, height = this.height, cells = this.cells; for (var y = height; y--;) { for (var x = width; x--;) { cells.unshift(new Cell(this, x, y)); } } }; Grid.prototype.getCell = function(x, y) { var width = this.width, height = this.height, cells = this.cells; if (x >= 0 && y >= 0 && x < width && y < height) { return cells[x + y * width]; } }; Grid.prototype.each = function(callback) { var cells = this.cells, cellCount = cells.length; for (var i = 0; i < cellCount; i++) { callback(cells[i], i); } }; // // GridDisplay // function GridDisplay(grid, element) { /** @type Grid */ this.grid = grid; /** @type Element */ this.element = element; } GridDisplay.prototype.drawCell = function(cell) { var display = this, button = document.createElement('button'); button.style.border = '1px outset white'; if (cell.value) { button.style.backgroundColor = 'black'; } button.onclick = function(event) { if (cell.value) { cell.value = false; } else { cell.value = true; } display.draw(); }; return button; }; GridDisplay.prototype.draw = function() { var display = this, grid = this.grid, buttons = this.element.getElementsByTagName('button'), container; if (buttons.length) { grid.each(function(cell, i) { if (cell.value) { buttons[i].style.backgroundColor = 'black'; } else { buttons[i].style.backgroundColor = null; } }); return; } this.element.innerHTML = ''; container = document.createElement('div'); grid.each(function(cell, i) { if (!cell.x) { container.appendChild(document.createElement('br')); } container.appendChild(display.drawCell(cell)); }); this.element.appendChild(container); }; // // Game // function Game(width, height, rule) { // The standard Game of Life is symbolised as "B3/S23": // A cell is "Born" if it has exactly 3 neighbours, // "Stays alive" if it has 2 or 3 living neighbours. var bornSurvive = rule.match(/\\d+/g); this.birthRule = bornSurvive[0]; this.survivalRule = bornSurvive[1]; this.grid = new Grid(width, height); this.gridDisplay = new GridDisplay(this.grid, board); this.gridDisplay.draw(); } Game.prototype.tick = function() { var grid = this.grid, survivalRule = this.survivalRule, birthRule = this.birthRule; grid.each(function(cell, i) { var neighbors = cell.getAdjacent(); var liveNeighborCount = 0; for (var j = 0; j < neighbors.length; j++) { if (neighbors[j].value) { ++liveNeighborCount; } } if (cell.value) { cell.nextValue = ~survivalRule.indexOf(liveNeighborCount); } else { cell.nextValue = ~birthRule.indexOf(liveNeighborCount); } }); grid.each(function(cell) { cell.value = cell.nextValue; }); this.gridDisplay.draw(); }; function createButton(label, callback) { var button = document.createElement('input'); button.type = 'button'; button.value = label; button.onclick = callback; document.body.appendChild(button); } var board = document.getElementById('board'); var game; var interval; createButton('new game', function() { clearInterval(interval); board.innerHTML = ''; game = new Game(50, 50, prompt('Enter a rule', 'B3/S23')); }); createButton('randomize', function() { var cells = game.grid.cells; clearInterval(interval); for (var i = 0; i < cells.length; i++) { cells[i].value = Math.random() * 2 | 0; } game.gridDisplay.draw(); }); createButton('step', function() { clearInterval(interval); game.tick(); }); createButton('go', function() { clearInterval(interval); interval = setInterval(function () { game.tick() }, 100); }); createButton('stop', function() { clearInterval(interval); }); 
 body { font: 10pt sans-serif; } div { font-size: 1px; } button { width: 8px; height: 8px; margin:0; padding: 0; vertical-align: middle; } 
 <div id="board"></div> 

It's quite an interesting idea using <div> s for this :)

Usually I really like SVG for graphics on the web, but this is a fine example where the <canvas> element just makes sense, I mean you basically work with pixels anyway.

So if you want to keep the <div> s follow Cerbrus' advice and get rid of hasClass() or at least try the native el.classList.contains() . That should be a lot quicker according to this jsperf . But it's always best to have it in a variable right in JS.

Just as a teaser, check out this canvas game of life: http://pmav.eu/stuff/javascript-game-of-life-v3.1.1/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM