Ошибка jQuery/Sizzle checkContext

Во время отладки моего приложения с помощью "Профилей" в DevTools я обнаружил, что "Частное дерево DOM" накопилось. Эти отдельные узлы имеют дерево сохранения, состоящее в основном из функций checkContext (исходящих из sizzle внутри jQuery - v1.10.1).

Heap snapshot

Я не уверен, как это сделать. Что означает этот результат?

Ответ 1

На самом деле это ошибка, нет причины, по которой Sizzle нужно висеть на контексте node, он делает это только потому, что не очищает после установки временной переменной. Я отправил вопрос для него, исправил его, выполнил все тесты Sizzle и выполнил запрос на перенос.

Если вы хотите исправить существующую копию jQuery или Sizzle:

  • Откройте файл jQuery или Sizzle

  • Найдите функцию matcherFromTokens

  • Найдите этот код в нем (вверху):

    matchers = [ function( elem, context, xml ) {
        return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
            (checkContext = context).nodeType ?
                matchContext( elem, context, xml ) :
                matchAnyContext( elem, context, xml ) );
    } ];
    
  • Измените return на var rv = и добавьте checkContext = undefined;, а затем return rv; в конце анонимной функции, например:

    matchers = [ function( elem, context, xml ) {
        var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
            (checkContext = context).nodeType ?
                matchContext( elem, context, xml ) :
                matchAnyContext( elem, context, xml ) );
        // Release the context node (issue #299)
        checkContext = null;
        return ret;
    } ];
    

Примечание. Этот код присваивает null checkContext, потому что, по-видимому, их стиль. Если бы это был я, я бы назначил undefined.

Если возникли проблемы с исправлением, возникшим во время процесса запроса/объединения, я обновлю ответ.

Лучше продолжать позволять Sizzle кеш-селекторам, потому что jQuery использует скомпилированный материал селектора с делегированием событий, и вы действительно не хотите, чтобы ему приходилось повторно обрабатывать и перестраивать функции сопряжения каждый раз, когда происходит соответствующее событие, чтобы оно могло фигурировать вне зависимости от того, соответствуют ли элементы.


Это не единственное место, к которому, к сожалению, относится к элементам скомпилированных селекторов. Каждое место, которое он делает, вероятно, является ошибкой, которая может использовать исправление. У меня было только время, чтобы выследить другого, о котором я также сообщал и исправил (в ожидании приземления запроса на тягу):

Если вы ищете "Потенциально сложные псевдо", вы найдете это для псевдоселектора :not:

pseudos: {
    // Potentially complex pseudos
    "not": markFunction(function( selector ) {
        // Trim the selector passed to compile
        // to avoid treating leading and trailing
        // spaces as combinators
        var input = [],
            results = [],
            matcher = compile( selector.replace( rtrim, "$1" ) );

        return matcher[ expando ] ?
            markFunction(function( seed, matches, context, xml ) {
                var elem,
                    unmatched = matcher( seed, null, xml, [] ),
                    i = seed.length;

                // Match elements unmatched by `matcher`
                while ( i-- ) {
                    if ( (elem = unmatched[i]) ) {
                        seed[i] = !(matches[i] = elem);
                    }
                }
            }) :
            function( elem, context, xml ) {
                input[0] = elem;
                matcher( input, null, xml, results );
                return !results.pop();
            };
    }),

Проблема заключается в функции после : в условном операторе:

function( elem, context, xml ) {
    input[0] = elem;
    matcher( input, null, xml, results );
    return !results.pop();
};

Обратите внимание, что он никогда не очищает input[0]. Здесь исправление:

function( elem, context, xml ) {
    input[0] = elem;
    matcher( input, null, xml, results );
    // Don't keep the element (issue #299)
    input[0] = null;
    return !results.pop();
};

Что у меня есть время для отслеживания в настоящее время.

Ответ 2

Sizzle хранит скомпилированные селекторы в кеш-селекторе, который по умолчанию хранит до 50 записей. Вы можете поэкспериментировать, установив $.expr.cacheLength = 1, прежде чем делать какие-либо выборы, и посмотреть, уходят ли они.

Здесь docs https://github.com/jquery/sizzle/wiki/Sizzle-Documentation#-internal-api. Кажется внутренним, поэтому не зависеть от него или чего-либо в фактическом производственном коде.