Что является заменойВсе производительности секрет? [Вызов HTML]

Я потратил некоторое время на лучший способ избежать html-строки и нашел некоторые дискуссии по этому поводу: обсуждение 1 обсуждение 2. Это приводит меня к replaceAll. Затем я сделал тесты производительности и попытался найти решение, добившееся такой же скорости без успеха: (

Вот мой окончательный набор тестов. Я нашел его в сети и расширил свои попытки (4 случая внизу) и до сих пор не может достичь производительности replaceAll().

Что такое секретная ведьма делает решение replaceAll() настолько быстрым?

Поздравил!

Фрагменты кода:

String.prototype.replaceAll = function(str1, str2, ignore) 
{
   return this.replace(new RegExp(str1.replace(/([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g,"\\$&"),(ignore?"gi":"g")),(typeof(str2)=="string")?str2.replace(/\$/g,"$$$$"):str2);
};

кредиты для qwerty

Самый быстрый случай:

html.replaceAll('&', '&amp;').replaceAll('"', '&quot;').replaceAll("'", '&#39;').replaceAll('<', '&lt;').replaceAll('>', '&gt;');

Ответ 1

Наконец-то я нашел его! Спасибо Jack за то, что указали мне на jsperf specific

Следует отметить, что результаты испытаний странные; когда .replaceAll() является определенный в Benchmark.prototype.setup, он работает в два раза быстрее по сравнению с тем, когда он определен глобально (т.е. внутри тега). Я все еще не уверен, почему это так, но это определенно должно быть связано с как работает jsperf.

Ответ:

replaceAll - это значение предела/ошибки jsperf, вызванное специальной последовательностью "\\$&", поэтому результаты были неправильными.

compile() - при вызове без аргумента он изменяет определение regexp на /(?:). Я не знаю, если это ошибка или что-то в этом роде, но результат производительности был дрянным после его вызова.

Вот мой результат безопасных тестов.

Наконец, я подготовил правильные тестовые примеры.

В результате, для HTML лучше всего использовать его для использования на основе собственного DOM-решения, например:

document.createElement('div').appendChild(document.createTextNode(html)).parentNode.innerHTML

или если вы повторяете это много раз, вы можете сделать это с помощью подготовленных переменных:

//prepare variables
var DOMtext = document.createTextNode("test");
var DOMnative = document.createElement("span");
DOMnative.appendChild(DOMtext);

//main work for each case
function HTMLescape(html){
  DOMtext.nodeValue = html;
  return DOMnative.innerHTML
}

Спасибо всем за сотрудничество и размещение комментариев и указаний.

описание ошибки jsperf

String.prototype.replaceAll определяется следующим образом:

function (str1, str2, ignore) {
  return this.replace(new RegExp(str1.replace(repAll, "\\#{setup}"), (ignore ? "gi" : "g")), (typeof(str2) == "string") ? str2.replace(/\$/g, "$$") : str2);
}

Ответ 2

Что касается производительности, я обнаружил, что функция ниже так же хороша, как и она:

String.prototype.htmlEscape = function() {
    var amp_re = /&/g, sq_re = /'/g, quot_re = /"/g, lt_re = /</g, gt_re = />/g;

    return function() {
        return this
          .replace(amp_re, '&amp;')
          .replace(sq_re, '&#39;')
          .replace(quot_re, '&quot;')
          .replace(lt_re, '&lt;')
          .replace(gt_re, '&gt;');
    }
}();

Он инициализирует регулярные выражения и возвращает замыкание, которое фактически выполняет замену.

Тест производительности

Следует отметить, что результаты испытаний странные; когда .replaceAll() определяется внутри Benchmark.prototype.setup, он работает в два раза быстрее, чем когда он определен глобально (т.е. внутри тега <script>). Я все еще не уверен, почему это так, но это определенно должно быть связано с тем, как работает jsperf.

Использование RegExp.compile()

Я хотел избежать использования устаревшей функции, главным образом потому, что этот вид производительности должен выполняться автоматически современными браузерами. Здесь версия с скомпилированными выражениями:

String.prototype.htmlEscape2 = function() {
    var amp_re = /&/g, sq_re = /'/g, quot_re = /"/g, lt_re = /</g, gt_re = />/g;

    if (RegExp.prototype.compile) {
        amp_re.compile();
        sq_re.compile();
        quot_re.compile();
        lt_re.compile();
        gt_re.compile();
    }

    return function() {
        return this
          .replace(amp_re, '&amp;')
          .replace(sq_re, '&#39;')
          .replace(quot_re, '&quot;')
          .replace(lt_re, '&lt;')
          .replace(gt_re, '&gt;');
    }
}

Делая это, удаляет все остальное из воды!

Тест производительности

Причина, по которой .compile() дает такое повышение производительности, заключается в том, что когда вы компилируете глобальное выражение, например. /a/g он преобразуется в /(?:)/ (в Chrome), что делает его бесполезным.

Если компиляция не может быть выполнена, браузер должен выкинуть ошибку, а не просто ее уничтожить.

Ответ 3

На самом деле есть более быстрые способы сделать это.

Если вы можете сделать встроенный сплит и присоединиться, вы получите лучшую производительность.

//example below
var test = "This is a test string";
var test2 = test.split("a").join("A");

Попробуйте это и запустите тест производительности.