Сохранить состояния объектов в .data или attr - Производительность против CSS?
В ответ на мой ответ вчера о вращении изображения Jamund сказал мне использовать .data()
вместо .attr()
Сначала я подумал, что он прав, , но потом я подумал о более широком контексте. Всегда ли лучше использовать .data()
вместо .attr()
? Я просмотрел некоторые другие сообщения, например what-is-better-data-or-attr или jquery-data-vs-attrdata
Ответы были неудовлетворительными для меня...
Итак, я перешел и отредактировал пример с помощью добавления CSS. Я думал, что было бы полезно сделать другой стиль на каждом изображении, если он вращается. Мой стиль был следующим:
.rp[data-rotate="0"] {
border:10px solid #FF0000;
}
.rp[data-rotate="90"] {
border:10px solid #00FF00;
}
.rp[data-rotate="180"] {
border:10px solid #0000FF;
}
.rp[data-rotate="270"] {
border:10px solid #00FF00;
}
Поскольку дизайн и кодирование часто разделяются, это может быть хорошей функцией для обработки этого в CSS вместо добавления этой функции в JavaScript. Кроме того, в моем случае data-rotate
похож на специальное состояние, которое в настоящее время имеет. Поэтому, на мой взгляд, имеет смысл представлять его в DOM.
Я также подумал, что это может быть случай, когда гораздо лучше сохранить .attr()
, а затем .data()
. Никогда не упоминалось ранее в одном из сообщений, которые я читал.
Но потом я подумал о производительности. Какая функция быстрее? Я построил свой собственный тест следующим образом:
<!DOCTYPE HTML>
<html>
<head>
<title>test</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript">
function runfirst(dobj,dname){
console.log("runfirst "+dname);
console.time(dname+"-attr");
for(i=0;i<10000;i++){
dobj.attr("data-test","a"+i);
}
console.timeEnd(dname+"-attr");
console.time(dname+"-data");
for(i=0;i<10000;i++){
dobj.data("data-test","a"+i);
}
console.timeEnd(dname+"-data");
}
function runlast(dobj,dname){
console.log("runlast "+dname);
console.time(dname+"-data");
for(i=0;i<10000;i++){
dobj.data("data-test","a"+i);
}
console.timeEnd(dname+"-data");
console.time(dname+"-attr");
for(i=0;i<10000;i++){
dobj.attr("data-test","a"+i);
}
console.timeEnd(dname+"-attr");
}
$().ready(function() {
runfirst($("#rp4"),"#rp4");
runfirst($("#rp3"),"#rp3");
runlast($("#rp2"),"#rp2");
runlast($("#rp1"),"#rp1");
});
</script>
</head>
<body>
<div id="rp1">Testdiv 1</div>
<div id="rp2" data-test="1">Testdiv 2</div>
<div id="rp3">Testdiv 3</div>
<div id="rp4" data-test="1">Testdiv 4</div>
</body>
</html>
Он также должен показать, есть ли разница с предопределенным data-test
или нет.
В результате получилось следующее:
runfirst #rp4
#rp4-attr: 515ms
#rp4-data: 268ms
runfirst #rp3
#rp3-attr: 505ms
#rp3-data: 264ms
runlast #rp2
#rp2-data: 260ms
#rp2-attr: 521ms
runlast #rp1
#rp1-data: 284ms
#rp1-attr: 525ms
Таким образом, функция .attr()
всегда нуждалась в большем количестве времени, чем функция .data()
. Это аргумент для .data()
, подумал я. Поскольку производительность всегда является аргументом!
Затем я хотел опубликовать свои результаты здесь с некоторыми вопросами, и в процессе написания я сравнил с вопросами, которые Qaru показал мне (похожие названия)
И правда, был один интересный пост о производительности
Я прочитал его и запустил их пример. И теперь я смущен! Этот тест показал, что .data()
медленнее, чем .attr()
!?!! Почему это так?
Сначала я подумал, что это из-за другой библиотеки jQuery, поэтому я ее отредактировал, а сохранил новый. Но результат не менялся...
Итак, теперь мои вопросы к вам:
- Почему существуют некоторые различия в производительности в этих двух примерах?
- Вы предпочитаете использовать атрибуты data-HTML5 вместо данных, если они представляют состояние? Хотя это было бы не нужно во время кодирования? Почему - почему бы и нет?
Теперь в зависимости от производительности:
- Будет ли производительность аргументом для использования
.attr()
вместо данных, если это показывает, что .attr()
лучше? Хотя данные предназначены для использования для .data()
?
ОБНОВЛЕНИЕ 1:
Я видел, что без накладных расходов .data()
выполняется намного быстрее. Непонятные данные:) Но меня больше интересует мой второй вопрос.:)
Предпочитаете ли вы использовать атрибуты data-HTML5 вместо данных, если это представляет состояние? Хотя это не было бы необходимо во время кодирование? Почему - почему бы и нет?
Есть ли другие причины, о которых вы можете думать, использовать .attr()
, а не .data()
? например совместимость? потому что .data()
- это стиль jquery, а атрибуты HTML могут быть прочитаны всеми...
ОБНОВЛЕНИЕ 2:
Как мы видим из TJ Crowder тест скорости в его ответ attr
намного быстрее, чем data
! что опять меня путает:) Но, пожалуйста! Производительность - это аргумент, но не самый высокий! Поэтому дайте ответы на мои другие вопросы, пожалуйста!
ОБНОВЛЕНИЕ 3:
Мой тест кажется ложным из-за fire-bug, который я использовал во время тестирования! Тот же самый файл в chrome, указанный attr
быстрее, а второй тест jsperf также говорит, что attr
быстрее
Ответы
Ответ 1
Эта рабочая часть вопроса кричит о преждевременной оптимизации; Смотри ниже. (Чтобы не возникла неправильная идея: я тоже часто виновата в том, что задаюсь вопросом о том же вопросе преждевременной оптимизации.)
Но получение производительности в сторону (другие точки, указанные ниже графика): насколько я могу судить, attr
быстрее, чем data
в jQuery 1.7.1: http://jsperf.com/jquery-setting-attr-vs-data Это меня удивляет. Не то чтобы это отдаленно могло иметь значение.
Графическая гистограмма (более длинные строки = более высокая производительность):
![Gratuitous bar graph from jsperf]()
Есть ли другие причины, о которых вы можете думать, использовать .attr(), а не .data()?
По крайней мере, пара приходит на ум:
-
Преимущество data
заключается в том, что ему не нужно каждый раз писать элемент; вы только пишете фактический элемент в первый раз, а с тех пор jQuery просто обновляет значение в объекте JavaScript, который он поддерживает в отдельном кеше объектов (подключен к элементу с помощью ключа). (Я не уверен, почему он медленнее, чем attr
, возможно, из-за косвенности.)
-
Мне не нравится то, что это не симметрично. При первом обращении к элементу data
объект данных засевается атрибутами data-*
от элемента; но оттуда, между ними нет никакой связи.
Пример (живая копия живой источник):
var target = $("#target");
display("data('foo'): " + target.data("foo"));
display("data-foo: " + target.attr("data-foo"));
display("Setting data('foo')");
target.data("foo", "updated data('foo')");
display("data('foo'): " + target.data("foo"));
display("data-foo: " + target.attr("data-foo"));
display("Setting data-foo");
target.attr("data-foo", "updated data-foo");
display("data('foo'): " + target.data("foo"));
display("data-foo: " + target.attr("data-foo"));
Предполагая, что элемент #target
начинается с data-foo="bar"
, вывод:
data('foo'): bar
data-foo: bar
Setting data('foo')
data('foo'): updated data('foo')
data-foo: bar
Setting data-foo
data('foo'): updated data('foo')
data-foo: updated data-foo
Это может быть запутанным и неожиданным. Способ, которым вы должны думать об этом, состоит в том, что атрибуты data-*
являются значениями по умолчанию. Мне просто не нравится, как они так зависят от того, вы назовете data
до или после; если вы никогда не напишете непосредственно в атрибуте data-*
, вы не можете быть уверены, какое значение data
получит (оригинал из разметки или значение, которое вы обновили позже, до того, как вы назовете data
)). Для меня это немного хаотично, но если вы устанавливаете правила (никогда не записывайте атрибуты data-*
напрямую и только когда-либо используете data
, например), вы можете избежать хаоса.
-
Когда вы используете attr
, вы можете хранить только строки. Когда вы используете data
, вы можете сохранить любое значение JavaScript или ссылку на объект.
Потому что производительность всегда является аргументом!
Не в 2012 году.:-) Или, по крайней мере, это намного ниже списка по сравнению с другими аргументами, чем когда-либо отсутствовало конкретная, очевидная проблема с производительностью.
Посмотрите на свои результаты runfirst #rp4
: 10k итераций attr
заняло 515ms; 10k итераций data
заняло 268 мс. Это 51,5 мкс (микросекунды, миллионные секунды секунды) по сравнению с 26,8 мксек каждый. Поэтому вам интересно, следует ли использовать data
, если он экономит вам 24,7 секунды на операцию. Люди воспринимают вещи порядка десятых долей секунды. Поэтому для этого важно, чтобы вы делали это примерно 4000 раз в узкой петле, чтобы человек заметил разницу. Это просто не стоит даже беспокоиться, даже в обработчике mousemove
.
Если вы находитесь на этой территории (4000/сек в узкой петле), вы, вероятно, захотите вообще не хранить информацию о элементе.
Ответ 2
Учитывая, что .data()
действительно медленнее, чем .attr()
в большинстве браузеров, но разница в скорости не важна в этом вопросе, одна преимущество data()
over attr()
заключается в том, что данные будут автоматически привязывать атрибуты data-
к значениям numbers
или boolean
, если они совпадают.
Это означает, что
<div id="boolean" data-t="true" data-f="false">
приведет к булевскому времени выполнения true
и false
при запуске:
console.log($('#boolean').data('t')); // reports true (not a string)
console.log($('#boolean').data('f')); // reports false (not a string)
и
<div id="number" data-n="123.456">
приведет к количеству значений времени выполнения 123.456
при запуске:
console.log($('#number').data('n')); // Reports 123.456 (not a string)
attr
, с другой стороны, работает только со строками, но преобразует значение в строки для сохранения. Он не будет вызывать ценности при их получении.
Выбор между attr
и data
зависит от функции, которая вам нужна для конкретного примера:
- Когда я ввожу параметры
data-
с сервера на страницы, я обычно использую data()
для доступа к ним, хотя бы потому, что это более короткий код.
- Если мне нужно, чтобы данные были видимыми в DOM, я буду использовать
attr()
для сохранения значений.
Ответ 3
Вы можете использовать jQuery.data. Это почти всегда самый быстрый. jQuery пытается оптимизировать свою функцию в каждом браузере и максимизировать совместимость. Таким образом, с новыми версиями jQuery вы можете получить производительность для этой функции.
Этот второй тест дал мне jQuery.data
победителем.