Javascript-форум (https://javascript.ru/forum/)
-   Firefox/Mozilla (https://javascript.ru/forum/css-html-firefox-mizilla/)
-   -   Оптимизация прорисовки таблицы (https://javascript.ru/forum/css-html-firefox-mizilla/6861-optimizaciya-prorisovki-tablicy.html)

frid-karatel 28.12.2009 09:49

Оптимизация прорисовки таблицы
 
В-общем, суть задачи, которую никак не могу решить более-менее правильно... И так, и так - не нравится скорость прорисовки - и все тут...

var myTable = [];//Массив строк, длина массива может быть и 1000
var myTableRow = [];//Каждый эл-нт массива myTable имеет еще массив, т.н. столбец. Столбцов может быть до 20ти штук
//Каждый столбец имеет свой тип. Например, если там число, то привести его в дату по шаблону "d.m.Y в H:i".
Если нарисовать структуру, то она будет такой:
myTable = {
	[Type:'int' or 'text', Value: '0-9' or 'azAZ'],
	...
	[Type:'int' or 'text', Value: '0-9' or 'azAZ']
};


В итоге, получается такой цикл для рисования этой таблицы
var rc = myTable.length;
var cc = myTable[0].length;//Каждая строка имеет одинаковое кол-во столбцов

var ri;
var ci;

var row;
var Result = [];
var c;

Result.push('<table><tbody>');
for (ri = 0; ri < rc; ri++) {
	row = [];
	for (ci = 0; ci < cc; ci++) {
		c = myTable[ri].Col[ci];
		switch(c.Type) {
			case 'int': {
				c = new Date(parseInt(c.Value));
				c = c.getDate();
			} break;
			case 'text': {
				c = '"' + c + '"';
			} break;
		}
		row.push(c);
	}
	Result.push('<tr><td>' + row.join('</td><td>') + '</td></tr>');
}
Result.push('</tbody></table>');

$(myTableArea).html(Result.join(''));


Проблема в том, что скорость такой "сборки" таблицы оставляет желать лучшего...
Например, у меня скорость такого алгоритма на 15 строк занимает где-то 300 мс.
Если строк не 15, а 100, то алгоритм занимает больше секунды.
А если 1000 строк нарисовать... То это вообще можно спать идти :)

Кто что подскажет?

PS: Разработка не кросс-браузерная, исключительно под Firefox.

Gvozd 28.12.2009 11:07

попробуй использовать вместо $().html(), который как я предполагаю является аналогом innerHTML, createElement
думаю этот метод займет чуточку больше времени на генерацию таблицы, но добавление собранной в памяти таблицы займет гораздо меньше времени, наверно

frid-karatel 28.12.2009 18:43

Цитата:

Сообщение от Gvozd (Сообщение 39404)
попробуй использовать вместо $().html(), который как я предполагаю является аналогом innerHTML, createElement
думаю этот метод займет чуточку больше времени на генерацию таблицы, но добавление собранной в памяти таблицы займет гораздо меньше времени, наверно

Не прибавило скорости... Даже убавило - 15 строк рисуются на 100 мс больше...

Заметил, что много времени (где-то 100-150 мс на 15 строк) тратится на удаление прошлой таблицы.

Например, мне надо вывести следующие 15 строк.
Я удаляю старую таблицу и создаю новую. Так вот, последующие создания (обновления) требуют на 100-150 мс больше...

Пытался заменить switch на массив из function, т.е.:
var fa = [];
for (ci = 0; ci < cc; ci++) {
	switch(myTable[0].Col[ci].Type) {
		case 'int': {
			fa[ci] = function(Col) {
				Col = new Date(parseInt(Col));
				Col = Col.getTime();
			};
		} break;
		case 'text': {
			fa[ci] = function(Col) {
				Col = '"' + Col + '"';
			};
		} break;
	}
}

И дальше вместо switch сразу вызывать функцию через fa[ci]( myTable[ri].Col[ci].Value).
Но это заняло на порядок больше времени, чем простой switch...

PS: А что, если в switch манипулировать цифрами, а не текстом?
Т.е. вместо int использовать 0, вместо text - 1?
С точки зрения машины, будет ли это производительней?

tenshi 28.12.2009 19:00

итерировать сначала по столбцам, а потом по строкам..

tenshi 28.12.2009 19:01

push умеет принимать несколько параметров

frid-karatel 28.12.2009 19:12

Цитата:

Сообщение от tenshi (Сообщение 39433)
итерировать сначала по столбцам, а потом по строкам..

Я, кстати, думал об этом... но не смог сообразить, как собрать таблицу :)

tenshi 28.12.2009 19:18

из дивов её собирать...

frid-karatel 28.12.2009 19:25

Цитата:

Сообщение от tenshi (Сообщение 39440)
из дивов её собирать...

Хм... насколько это будет правильно?
100 строк по 10 столбцов в каждой - это 1000 DIV'ов...

Не будет ли это сложновато для отрисовки? :blink:

tenshi 28.12.2009 19:41

думаешь 1000 ячеек будет проще? х)

frid-karatel 28.12.2009 19:51

Цитата:

Сообщение от tenshi (Сообщение 39449)
думаешь 1000 ячеек будет проще? х)

Ну... с точки зрения наглядности - проще ими управлять :) Например, закрасить ячейки в строке в другой цвет... Или поменять ширину колонки...

Kolyaj 29.12.2009 09:44

frid-karatel,
попробуй разбить таблицу из 1000 строк на 10 таблиц из 100 строк.

subzey 29.12.2009 11:09

Дело именно в отрисовке?
Попробуйте найти узкое место - запустите цикл "вхолостую", с записью не в innerHTML, а в какую-нибудь левую переменную;
в реальную таблицу, у которой display:none;
в реальную таблицу, у которой table-layout: fixed.

Просто возможно, что тормозит не математика и DOM, а reflow.

frid-karatel 29.12.2009 13:04

Код:
TABLE.prototype.Print = function() {
  this.Sort();
  /*
  Сортировка по принципу вызова доп. функции к эл-ту
  т.е.
  if (a > b)
    return 1;
  else
    return -1;
  return 0;
  */
  for (ri = 0; ri < rc; ri++) {
    for (ci = 0; ci < cc; ci++) {
      switch(...) {
        /* как бы array.push(...) */
      }
    }
  }
  document.body.innerHTML = array.join('');
}


Вот результаты:
- Весь код ~ 296 мс
- Без вывода в innerHTML ~ 66 мс
- Без вывода в innerHTML + без сортировки ~ 12 мс

subzey 29.12.2009 14:48

Дело в рендеринге. Быстрее, чем Fx сможет нарисовать эту таблицу, показаться она не сможет.

Кстати, я тут бенчмарк небольшой устроил — вывод таблицы 10×1000 занял…
Opera 10: 10 секунд
Opera 10.50a: 17 секунд (они делают ее медленнее?!)
Firefox 3.5: 24 секунды
Chrome: 4 секунды
IE8: 14 секунд

tenshi 29.12.2009 14:54

а теперь сделай её фиксированой..

frid-karatel 29.12.2009 15:01

Цитата:

Сообщение от tenshi (Сообщение 39511)
а теперь сделай её фиксированой..

В каком плане?

Кстати, был у меня интересный вариант в плане "усовершенствования"...
В частности, на C++ такой вариант работал - это создание сразу 1000 строк, а потом скрывать те, которые не нужны...

То есть создать один раз таблицу, а затем ее заполнять... Если строк всего 100 штук, то остальные 900 штук сделать display:none..

Как такой вариант?

Kolyaj 29.12.2009 15:52

Цитата:

Сообщение от subzey
Кстати, я тут бенчмарк небольшой устроил — вывод таблицы 10×1000 занял…

А теперь 10 таблиц 10х100.

tenshi 29.12.2009 15:54

table-layout:fixed

frid-karatel 29.12.2009 17:35

Цитата:

Сообщение от tenshi (Сообщение 39523)
table-layout:fixed

В стилях это прописано ;)

Блин, почему же у лиса такой "не шустрый" JS движок... мне кажется, это должно быть одним из основных направлений разработки браузеров, т.к. все активней используется генерация страницы на компьютере пользователя...

Вот запустил этот код на Chrome - 88 мс (!) против ~300 Firefox'а... капец... :blink:


Часовой пояс GMT +3, время: 08:58.